Monorepo Architecture
Purpose and Scope
Cal.diy is organized as a private Yarn workspace monorepo for a self-hosted scheduling platform. The repository README frames the project as the community-driven, fully open-source edition of Cal.com, intended for individuals and self-hosters who run their own instance rather than a hosted service. That product boundary matters for contributors: the monorepo contains the web application, API proxy, app-store tooling, embeds, platform packages, shared libraries, and test surfaces needed to operate and evolve the self-hosted distribution, while the README explicitly warns that operators remain responsible for server administration, database management, and securing sensitive data.
Sources: README.md, package.json
The top-level package manifest is the main architectural index. It declares the repository private, names it as the Cal.com monorepo, and defines workspace globs for application folders, nested API applications, shared packages, feature packages, app-store packages, platform packages, the base platform example, and example apps. This means contributors should treat dependency boundaries as workspace package boundaries, not as a single flat application. The root scripts then provide the supported ways to invoke builds, development servers, database tasks, app-store generation, embed publishing, linting, formatting, and tests across that workspace graph.
Sources: package.json
Relevant Source Files
- package.json — Defines the private workspace root, workspace globs, and contributor-facing scripts for builds, development, database operations, app-store tooling, embed publishing, linting, formatting, and tests.
- turbo.json — Configures the Turborepo task environment, including the lockfile as a global dependency and the environment variables that can affect cached task output.
- README.md — Describes the project purpose, self-hosting warning, Cal.diy versus Cal.com positioning, technology stack, and baseline prerequisites.
- apps/web/package.json — Defines the primary Next.js web app package, its development/build/start scripts, workspace dependencies, and expected Yarn engine.
- apps/api/package.json — Defines the lightweight API proxy application package and the script/dependencies used to run it in development.
Workspace Layout
The workspace list in the root manifest is broad enough to support several contributor roles. Application work lives under app-oriented workspace globs, package work lives under shared package globs, and integrations are split between the aggregate app-store package and individual app-store app packages. Embeds and platform atoms also receive their own nested workspace patterns, which is important because those surfaces can be built, tested, or published independently from the main web app. Example applications are included as workspaces too, so demonstration code can depend on the same local packages as production code without publishing interim versions.
Sources: package.json
A practical way to read the layout is to start from the runtime shell and move outward. The web application is the main user-facing Next.js package. It depends on workspace packages for the app store, embed runtime, feature modules, shared library code, platform types and enums, Prisma access, TRPC, TypeScript configuration, and UI components. That dependency list shows the intended direction: the application composes reusable packages rather than duplicating integration, database, interface, or API-client logic inside the app folder. For maintainers, changes to shared packages should be evaluated by their downstream effect on the web package.
Sources: apps/web/package.json
The API package named as the API proxy is much smaller. Its manifest exposes a development script that runs a Node entrypoint and lists only a compact set of proxy-oriented dependencies: Connect, the Node HTTP compatibility package, and HTTP proxy middleware. At the root, scripts such as the API development commands combine the web application with this proxy through Turbo filters. That separation lets contributors run the web app alone for ordinary UI work, or run the web app plus API proxy when validating API v2 or proxy-dependent behavior.
Sources: apps/api/package.json, package.json
Top-Level Script Model
The root scripts are not just conveniences; they are the standard public interface for contributor workflows. The default development command runs the Turbo development task filtered to the web package. Other development commands widen the graph by adding the API proxy, console, website, swagger app, AI package, or trigger-related feature tasks. This filter-based model keeps routine local development focused while still allowing multi-service scenarios to be reproduced from the root. Contributors should prefer these root commands because they encode the package combinations that the maintainers expect to work together.
Sources: package.json
Build and start flows follow the same pattern. The root build command invokes Turbo over the web package and its dependency graph, while the start command runs the start task filtered to the web package. The web package then maps those abstract tasks to Next.js behavior: development copies app-store static assets before starting Next.js with Turbopack, production build runs Next.js build and then creates a Sentry release, and start delegates to Next.js start. This two-layer design keeps package-specific details inside each package while retaining root-level orchestration for contributors and deployment scripts.
Sources: package.json, apps/web/package.json
Database and environment scripts are centralized at the workspace root because they affect multiple packages. The root manifest exposes Prisma through the Prisma workspace, adds scripts for deploy, seed, and studio tasks, and includes environment-check commands for the common environment file and app-store environment file. It also provides Infisical-backed variants for development and example environment generation. These scripts signal that database state and secrets are shared concerns, not local implementation details of one package. When a contributor changes schema, app-store credentials, or deployment configuration, root-level commands are the safest coordination point.
Sources: package.json
Turbo Task and Environment Boundaries
The Turbo configuration treats the lockfile as a global dependency, so dependency resolution changes can invalidate cached work across the repository. It also declares a long global environment allowlist covering hostnames, build flags, database URLs, cron secrets, integration credentials, email settings, public Next.js variables, testing credentials, payment keys, calendar/video provider settings, telemetry flags, and embed configuration. This is significant because many packages are sensitive to runtime configuration even when their source files do not change. A cached build that ignores these values could be incorrect, so the monorepo records them as task inputs.
Sources: turbo.json
For maintainers, the global environment list is a map of cross-cutting operational concerns. It includes database connection variables, app credentials, OAuth provider keys, email transport settings, public web configuration, Stripe and Daily values, cron secrets, test-mode values, and embed URLs. The presence of both private and public variables also clarifies that this repository has server-rendered, client-rendered, scheduled, integration, and test execution contexts. When adding a package that depends on a new environment variable during build, test, or development, the variable should be considered for Turbo configuration so task caching remains accurate.
Sources: turbo.json
Major Application Packages
The web package is the primary application surface for most contributors. Its script list covers bundle analysis, local development, HTTPS development, cron testing, Playwright code generation, TypeScript checking, linting, static app-store copying, translation checks, and Stripe webhook forwarding. Those scripts reveal common maintenance loops: UI iteration, scheduled-job validation, type safety, localization integrity, payment testing, and production build verification. The package also pins a Yarn engine version, which is useful when diagnosing workspace install differences or dependency resolution problems across machines.
Sources: apps/web/package.json
The web package dependencies show that Cal.diy uses a mix of local workspace packages and third-party libraries. Local dependencies include app-store packages, dayjs helpers, embed packages, feature modules, shared libraries, platform packages, Prisma, TRPC, UI, and shared TypeScript configuration. Third-party dependencies include Next.js-adjacent tooling, authentication, calendar integrations, form handling, Sentry, Stripe, React Query, Redis, and provider SDKs. The important architectural point is not the full dependency catalog; it is that the web app is the composition layer where scheduling UI, integrations, persistence, API access, and shared design primitives meet.
Sources: apps/web/package.json
The API proxy package is deliberately narrow compared with the web app. It is a private workspace named for the Cal.com API proxy, and its development command runs a Node process directly. Root development scripts place it beside the web package when API work is needed, including API, API-plus-console, AI, and Swagger-oriented flows. This tells contributors not to assume every API path is owned by the Next.js package. Some local development scenarios require a companion proxy process so that requests, documentation surfaces, or API v2 behavior can be exercised in a topology closer to the intended service layout.
Sources: apps/api/package.json, package.json
Contributor Workflow Guidance
A new contributor should begin by identifying whether the change is application-facing, package-facing, integration-facing, or tooling-facing. Application-facing web changes normally start with the root development script for the web package, then use web-package scripts for type checks, linting, or focused local helpers. API proxy changes should use the root scripts that include the proxy rather than only running the web app. App-store or embed work should use the dedicated root commands because those workflows include package-specific build, watch, template, creation, deletion, or publishing behavior encoded in the root manifest.
Sources: package.json, apps/web/package.json, apps/api/package.json
The root manifest also exposes quality and release-oriented commands that help keep the monorepo consistent. Formatting is handled through Biome, linting is routed through Turbo, end-to-end tests use Playwright with package-specific projects, embed tests have quick and full variants, and postinstall runs Husky plus package post-install tasks. Cleanup removes common generated directories across the tree. These scripts are useful when moving between branches or after changing dependency graph shape, because generated outputs and cached artifacts can otherwise make workspace behavior look different from the actual source state.
Sources: package.json
Next Steps
Use the architecture above as a routing guide before editing code. For local product work, continue to the source-based setup and web application pages. For API service behavior, read the API v2 overview and API service pages. For integration development, use the app-store package and CLI pages. For embeddable scheduling surfaces, read the embeds overview and package-specific embed pages. For shared UI, i18n, TRPC, email templates, and testing utilities, follow the related package reference pages so changes are made at the correct layer rather than duplicated in the application shell.
Sources: README.md, package.json