Skip to main content

Monorepo Structure

Cal.com uses a Yarn/Turbo monorepo architecture with multiple applications and shared packages.
cal.com/
├── apps/
│   ├── web/              # Main Next.js application
│   └── api/              # API applications
│       ├── v1/           # Legacy API (v1)
│       └── v2/           # Platform API (v2)
├── packages/
│   ├── app-store/        # Third-party integrations
│   ├── features/         # Feature-specific code (73 features)
│   ├── prisma/           # Database schema and migrations
│   ├── trpc/             # tRPC API layer
│   ├── ui/               # Shared UI components
│   ├── lib/              # Shared utilities (32 libraries)
│   ├── platform/         # Platform SDK and libraries
│   ├── emails/           # Email templates
│   ├── embeds/           # Embed packages
│   └── i18n/             # Internationalization
└── turbo.json            # Turborepo configuration

Key Directories

Apps

apps/web/

The main Next.js 13+ application using App Router. Key subdirectories:
  • app/ - App Router pages and layouts
  • pages/ - Legacy Pages Router routes
  • public/ - Static assets
  • components/ - Web-specific components

apps/api/v1/

Legacy REST API for public consumption.

apps/api/v2/

New Platform API with enhanced capabilities.
When importing from @calcom/features or @calcom/trpc into apps/api/v2, re-export from packages/platform/libraries/index.ts and import from @calcom/platform-libraries to avoid module resolution issues.

Packages

packages/prisma/

Central database management. Key files:
  • schema.prisma - Database schema definition
  • migrations/ - Database migration files
  • seed.ts - Database seeding script

packages/trpc/

Type-safe API layer using tRPC. Structure:
  • server/routers/ - API endpoint definitions
  • react/ - React hooks for tRPC

packages/features/

Feature-based organization (73 features). Examples:
  • bookings/ - Booking logic
  • ee/ - Enterprise features
  • auth/ - Authentication
  • calendars/ - Calendar integrations
  • webhooks/ - Webhook handling

packages/app-store/

Third-party integrations (112 apps). Structure:
  • Each app has its own directory
  • config.json - App configuration
  • api/ - API endpoints
  • lib/ - Business logic
  • components/ - UI components

packages/ui/

Shared UI component library. Components:
  • Buttons, forms, modals
  • Design system primitives
  • Tailwind-based styling

packages/lib/

Shared utilities and helpers (32 libraries). Examples:
  • Date/time utilities
  • Validation helpers
  • Type definitions
  • Constants

Tech Stack

Frontend

  • Framework: Next.js 13+ (App Router + Pages Router)
  • Language: TypeScript (strict mode)
  • Styling: Tailwind CSS
  • UI Library: Custom component library (@calcom/ui)
  • State Management: React hooks + tRPC
  • Forms: React Hook Form
  • Internationalization: next-i18next

Backend

  • API: tRPC for type-safe APIs
  • Database: PostgreSQL
  • ORM: Prisma
  • Authentication: NextAuth.js
  • Validation: Zod schemas
  • Email: SendGrid, Nodemailer
  • SMS: Twilio

Testing

  • Unit Tests: Vitest
  • E2E Tests: Playwright
  • Mocking: Prismock (Prisma), vitest-mock-extended

Build & Development

  • Monorepo: Turborepo
  • Package Manager: Yarn (v4.12.0)
  • Linting: Biome
  • Formatting: Biome
  • Type Checking: TypeScript compiler

Infrastructure

  • Deployment: Vercel, Docker
  • CI/CD: GitHub Actions
  • Monitoring: Sentry
  • Analytics: PostHog
  • Rate Limiting: Unkey (optional)

Database Architecture

Schema Location

packages/prisma/schema.prisma

Key Models

  • User - User accounts
  • Team - Team/organization data
  • EventType - Event type configurations
  • Booking - Booking records
  • Availability - User availability schedules
  • Credential - Integration credentials
  • Webhook - Webhook configurations
  • Payment - Payment records
  • Workflow - Automation workflows
Security: Never expose the credential.key field in API responses or queries. Always use select instead of include in Prisma queries.

API Architecture

tRPC Routers

Located in packages/trpc/server/routers/:
// Example router structure
router/
├── viewer/
│   ├── bookings.router.ts
│   ├── eventTypes.router.ts
│   ├── availability.router.ts
│   └── auth.router.ts
└── public/
    └── slots.router.ts

Error Handling

  • tRPC Routers: Use TRPCError
  • Services/Repositories: Use ErrorWithCode
  • Always provide descriptive error messages with context

Routing

App Router (Next.js 13+)

Primary routing system in apps/web/app/:
app/
├── (public)/
│   └── [user]/[type]/page.tsx    # Booking page
├── (dashboard)/
│   ├── event-types/page.tsx
│   ├── bookings/page.tsx
│   └── settings/page.tsx
└── api/
    └── trpc/[trpc]/route.ts
Permission checks must be in page.tsx, never in layout.tsx.

Pages Router (Legacy)

Legacy routes in apps/web/pages/:
pages/
├── api/
│   ├── auth/[...nextauth].ts
│   └── trpc/[trpc].ts
└── [user]/[type].tsx              # Legacy booking page

Component Organization

Shared Components

packages/ui/components/
├── button/
├── form/
├── dialog/
├── tooltip/
└── ...
Import directly from source:
// Good
import { Button } from "@calcom/ui/components/button";

// Bad - don't use barrel imports
import { Button } from "@calcom/ui";

Feature Components

packages/features/<feature>/components/
Each feature can contain its own components.

Service Layer

Architecture Pattern

Controller (tRPC Router)

Service Layer (Business Logic)

Repository Layer (Data Access)

Database (Prisma)

File Naming Conventions

Services

// File: MembershipService.ts
export class MembershipService { ... }

// File: HashedLinkService.ts
export class HashedLinkService { ... }

Repositories

// File: PrismaAppRepository.ts
export class PrismaAppRepository { ... }

// File: PrismaMembershipRepository.ts
export class PrismaMembershipRepository { ... }
  • File names must match exported class names (PascalCase)
  • Never put business logic in repositories
  • Avoid generic names like AppService.ts

Build System (Turborepo)

Key Commands

Defined in turbo.json:
  • build - Build all packages and apps
  • dev - Start development servers
  • lint - Run linters
  • type-check - Type check all packages
  • test - Run unit tests
  • db-migrate - Run database migrations

Task Dependencies

Turborepo manages dependencies between tasks:
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    }
  }
}

Configuration Files

Key Files

  • package.json - Root package configuration
  • turbo.json - Turborepo configuration
  • tsconfig.json - TypeScript base configuration
  • .env.example - Environment variable template
  • .env.appStore.example - App Store environment variables
  • biome.json - Biome linting/formatting config

TypeScript Configuration

Shared configs in packages/tsconfig/:
  • base.json - Base TypeScript config
  • nextjs.json - Next.js specific config
  • react-library.json - React library config

Deployment Architecture

Vercel Deployment

  • Main app: apps/web
  • API routes: Serverless functions
  • Static assets: CDN

Docker Deployment

docker-compose.yml
├── calcom (web app)
├── database (PostgreSQL)
└── studio (Prisma Studio)

Environment Variables

See turbo.json for the complete list of 300+ environment variables. Critical variables:
  • DATABASE_URL - Database connection
  • NEXTAUTH_SECRET - Auth secret
  • CALENDSO_ENCRYPTION_KEY - Encryption key
  • NEXT_PUBLIC_WEBAPP_URL - Base URL

Next Steps

Build docs developers (and LLMs) love