Open-Source Wikis

/

Cal.com

/

Cal.diy

/

Architecture

calcom/cal.com

Architecture

Cal.diy is a Yarn 4 + Turborepo monorepo containing three deployable apps and ~30 shared workspace packages. The default deployment is the Next.js web app (apps/web) connected to a PostgreSQL database; everything else is optional.

Top-level layout

cal.com/
├── apps/
│   ├── web/              # Next.js 13+ App Router — the main product
│   ├── api/v2/           # NestJS REST API (Cal.com Platform v2)
│   ├── api/index.js      # Thin proxy entry for legacy API routing
│   └── docs/             # MintLify documentation site
├── packages/
│   ├── features/         # 70+ feature modules (bookings, eventtypes, slots, ...)
│   ├── lib/              # Shared utilities (CalendarService, dayjs, crypto, ...)
│   ├── ui/               # Shared design system (Button, Form, Dialog, ...)
│   ├── prisma/           # Database schema, migrations, seed scripts
│   ├── trpc/             # tRPC routers + client wiring
│   ├── app-store/        # 100+ integrations (calendars, video, payments, CRM, ...)
│   ├── app-store-cli/    # Code generator that wires apps into the registry
│   ├── embeds/           # embed-core, embed-react, embed-snippet
│   ├── platform/         # NestJS API SDK + React "atom" components
│   ├── emails/           # Transactional email templates
│   ├── dayjs/            # Pre-configured Day.js bundle with plugins
│   ├── debugging/        # Logger, troubleshooter helpers
│   ├── di/               # Dependency injection helpers
│   ├── kysely/           # Generated Kysely types from Prisma
│   ├── i18n/             # next-i18next locales (en is canonical)
│   ├── sms/              # SMS providers (Twilio, etc.)
│   ├── trpc/             # tRPC server + client
│   ├── types/            # Shared TypeScript types
│   ├── tsconfig/         # Shared tsconfig presets
│   └── ... (config, coss-ui, embeds, testing, kysely)
├── example-apps/         # Sample integrations
├── deploy/               # Deployment helpers
├── scripts/              # SQL helpers + seeding scripts
└── specs/                # Spec-driven-development specs

Runtime architecture

graph TD
    subgraph Browser
        WebApp[apps/web Next.js client]
        Embeds[embed-core / embed-react]
        Atoms[platform/atoms]
    end

    subgraph "Next.js server (apps/web)"
        AppRouter[App Router routes]
        PagesRouter[pages/ legacy routes]
        TRPCServer[tRPC routers @calcom/trpc]
        NextAuth[NextAuth.js]
    end

    subgraph "NestJS server (apps/api/v2)"
        REST[REST controllers]
        OAuthClients[OAuth clients module]
        PlatformSDK[Platform SDK endpoints]
    end

    subgraph "Background"
        Trigger[Trigger.dev jobs]
        Cron[GitHub Actions crons]
        Tasker[features/tasker queue]
    end

    subgraph Data
        Postgres[(PostgreSQL via Prisma)]
        Redis[(Redis cache + rate limit)]
    end

    subgraph "Third party"
        Calendars[Calendar APIs]
        Video[Video providers]
        Payments[Stripe / PayPal / HitPay]
        Email[SendGrid / SMTP]
        SMS[Twilio]
    end

    WebApp -->|tRPC HTTP| TRPCServer
    WebApp -->|NextAuth| NextAuth
    Embeds -->|loads| WebApp
    Atoms -->|REST| REST

    TRPCServer --> Postgres
    REST --> Postgres
    NextAuth --> Postgres
    TRPCServer --> Redis
    REST --> Redis

    TRPCServer --> Calendars
    REST --> Calendars
    Trigger --> Postgres
    Tasker --> Postgres
    Cron -->|HTTP| AppRouter

    AppRouter --> Email
    AppRouter --> SMS
    AppRouter --> Payments
    REST --> Video

The web app is the primary entry point for end users and embeds. It serves marketing pages, booking pages, the authenticated dashboard, and a tRPC HTTP endpoint at /api/trpc/[trpc] (see apps/web/pages/api/trpc/[trpc].ts and packages/trpc/server/createNextApiHandler.ts). The NestJS API in apps/api/v2 is deployed separately and powers the official REST API plus the Platform SDK ("atoms"). Background jobs run through Trigger.dev and cron-style GitHub Actions workflows that hit internal HTTP endpoints.

Request lifecycle: a public booking

sequenceDiagram
    participant Visitor
    participant Web as apps/web
    participant TRPC as packages/trpc
    participant Slots as features/slots
    participant Calendars as features/calendars
    participant Booking as features/bookings
    participant DB as PostgreSQL

    Visitor->>Web: GET /[username]/[eventType]
    Web->>TRPC: viewer.public.event + slots.getSchedule
    TRPC->>Slots: getAvailableSlots
    Slots->>Calendars: getBusyTimes (Google/MS/Apple/CalDAV)
    Calendars-->>Slots: busyIntervals
    Slots-->>TRPC: timeSlots
    TRPC-->>Web: render slot picker
    Visitor->>Web: POST /api/book/event
    Web->>Booking: handleNewBooking
    Booking->>DB: create Booking + BookingReference
    Booking->>Calendars: create event in destination calendar
    Booking->>Web: emit webhooks, send emails, schedule reminders
    Web-->>Visitor: redirect to /booking/[uid]

The end-to-end flow lives mostly in packages/features/bookings/lib/handleNewBooking/ (split into many submodules) and packages/features/slots. Calendar federation is handled through adapters in packages/app-store/<provider>/lib/CalendarService.ts, all conforming to the shared Calendar interface in packages/types/Calendar.d.ts.

Core architectural patterns

  • Repository / service split. packages/features/<domain>/repositories/*Repository.ts wrap Prisma queries and never contain business logic. packages/features/<domain>/services/*Service.ts orchestrate repositories and external calls. tRPC handlers and REST controllers stay thin and delegate to services. The convention is documented in AGENTS.md and reinforced by agents/rules/quality-architecture.md.
  • Dependency injection. Each domain has a di/ directory (e.g., packages/features/bookings/di) using a small homegrown container in packages/features/di/. This decouples handlers from repository implementations and makes testing simpler.
  • Generated app metadata. packages/app-store-cli walks packages/app-store/* and emits the *.generated.ts files (apps.metadata.generated.ts, apps.server.generated.ts, bookerApps.metadata.generated.ts, etc.). AGENTS.md calls out that these files must never be hand-edited.
  • Path-based imports. The codebase deliberately avoids barrel index.ts re-exports — AGENTS.md mandates import { Button } from "@calcom/ui/components/button" rather than import { Button } from "@calcom/ui".
  • Type-safe API. tRPC carries TypeScript types from server to client without code generation, while apps/api/v2 uses Zod schemas (packages/platform/types) shared between request validation and the Platform SDK.
  • Feature flags. packages/features/flags provides a database-backed flag service used to gate experimental code (e.g., packages/features/flags/features.repository.ts).

Two API surfaces

The repo intentionally exposes two API layers, each with its own audience:

Surface Path Used by Auth
tRPC packages/trpc/server/routers/ mounted at apps/web/pages/api/trpc/[trpc].ts The web app and embeds NextAuth session cookie
REST v2 apps/api/v2/src/modules/** Platform SDK consumers, third-party integrators API keys, OAuth, JWT

A legacy pages/api/v1/ directory under apps/web/pages/api mirrors a subset of the REST surface for backward compatibility. The proxy in apps/web/proxy.ts decides how requests are routed across these surfaces.

Where to look next

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Architecture – Cal.com wiki | Factory