Open-Source Wikis

/

Cal.com

/

Apps

/

Web

calcom/cal.com

Web

Active contributors: Romit, Eunjae, Pedro, Hariom, Benny

Purpose

apps/web is the main Cal.diy product — the Next.js 13+ application that serves the marketing pages, the public booking pages, the authenticated dashboard, the embed runtime entry, and the tRPC HTTP endpoint that the rest of the front end (and embeds) call. It is the only app most self-hosted instances actually deploy.

Directory layout

apps/web/
├── app/                       # Next.js App Router routes
│   ├── (booking-page-wrapper)/  # Public booking flow group
│   ├── (use-page-wrapper)/      # Authenticated app group (settings, bookings, ...)
│   ├── api/                     # App Router API handlers
│   ├── cache/                   # Cache utilities
│   ├── e2e/                     # E2E helper routes (only in test builds)
│   ├── error.tsx, global-error.tsx
│   ├── icons/, fonts/, public/
│   ├── layout.tsx, page.tsx
│   └── not-found.tsx, notFoundClient.tsx
├── pages/                     # Pages Router (legacy API + a few pages)
│   └── api/                     # 39 legacy API endpoints
├── components/                # Shared React components specific to the web app
├── modules/                   # 35 feature modules (api-keys, bookings, event-types, ...)
├── lib/                       # App-local utilities
├── server/                    # Server-only helpers
├── playwright/                # E2E specs
├── public/                    # Static assets, including i18n locales
├── scripts/                   # Build/runtime helpers
├── proxy.ts                   # Reverse-proxy logic for routing across surfaces
├── proxy.test.ts              # Tests for proxy.ts
├── instrumentation.ts         # Sentry instrumentation entry
├── instrumentation-client.ts  # Browser-side Sentry init
├── sentry.server.config.ts
├── sentry.edge.config.ts
├── next.config.ts             # 19 KB next.config — feature flags, headers, rewrites
├── pagesAndRewritePaths.ts    # Centralized rewrite/redirect rules
├── getNextjsOrgRewriteConfig.ts
├── trigger.version.ts
└── package.json

App Router groups

apps/web/app/(use-page-wrapper)/(main-nav)/ is the authenticated dashboard:

Path Purpose
event-types/ Manage your bookable offerings
bookings/ Past, upcoming, cancelled bookings
availability/ Schedule editor
members/ Team members (where applicable)
booking/, apps/web/app/(booking-page-wrapper) Booking detail + public booking flow

Other top-level App Router groups: auth, apps, signup, onboarding, settings, payment, video, enterprise (legacy, being removed), more, refer, upgrade, getting-started, maintenance.

Pages Router

apps/web/pages/api/ retains 39 legacy API routes. The most important is pages/api/trpc/[trpc].ts, which mounts every tRPC router. The rest are integration callbacks (OAuth redirects, webhook receivers from Stripe / Daily / etc.) that have not yet been ported to the App Router.

Modules

apps/web/modules/ contains 35 directories — one per UI feature. They are the page-level glue between packages/features/<domain>/ (business logic + components) and the App Router pages. For example:

  • apps/web/modules/event-types/ — event-type editor screens
  • apps/web/modules/bookings/ — bookings list + detail
  • apps/web/modules/availability/ — schedule UI
  • apps/web/modules/auth/ — login, signup, magic-link forms
  • apps/web/modules/onboarding/, getting-started/ — first-time setup wizard
  • apps/web/modules/embed/ — embed-specific routes and SSR
  • apps/web/modules/troubleshooter/ — availability troubleshooter

The pattern is intentional: thin app/.../page.tsx files import a View component from apps/web/modules/<feature>/, which composes pieces from packages/features/<feature>/components/ and packages/ui/.

Key abstractions

Symbol File Purpose
WithEmbedSSR apps/web/app/WithEmbedSSR.tsx Wraps a page with embed-aware server rendering
WithAppDirSsr apps/web/app/WithAppDirSsr.tsx Bridge for SSR helpers between Pages and App Router
AppRouterI18nProvider apps/web/app/AppRouterI18nProvider.tsx Loads i18n bundles for App Router pages
pagesAndRewritePaths apps/web/pagesAndRewritePaths.ts Single list of paths the proxy + rewrites need to know about
proxy.ts apps/web/proxy.ts Routes incoming traffic across legacy and new surfaces
next.config.ts apps/web/next.config.ts Feature flags, security headers, rewrites, image config
trigger.version.ts apps/web/trigger.version.ts Pinned Trigger.dev SDK version

How it works

graph TD
    Visitor -->|HTTP| Proxy[apps/web/proxy.ts]
    Proxy -->|App Router| AppRouter[app/]
    Proxy -->|Pages Router| Pages[pages/]
    AppRouter -->|tRPC HTTP| TRPCEndpoint[pages/api/trpc/[trpc].ts]
    TRPCEndpoint -->|delegates| TRPCServer[packages/trpc routers]
    AppRouter -->|loadable| Modules[apps/web/modules/*]
    Modules --> Features[packages/features/*]
    Pages -->|webhooks| Features
    NextAuth[NextAuth callbacks] --> AuthFeature[packages/features/auth]

A typical authenticated request flow:

  1. The browser hits an App Router route like /event-types.
  2. Next.js resolves the layout chain. Permission checks happen in page.tsx (per AGENTS.md).
  3. The page imports a View from apps/web/modules/event-types/. The View pulls data via tRPC client hooks generated from packages/trpc.
  4. tRPC calls land at pages/api/trpc/[trpc].ts, which delegates to packages/trpc/server/createNextApiHandler.ts.
  5. Routers under packages/trpc/server/routers/ invoke services in packages/features/<domain>/services which call repositories which talk to Prisma.

Public booking flow uses the (booking-page-wrapper) group and similarly threads through packages/features/bookings.

Integration points

  • NextAuthpages/api/auth/[...nextauth].ts mounts NextAuth using packages/features/auth/lib/next-auth-options.ts and the custom adapter packages/features/auth/lib/next-auth-custom-adapter.ts.
  • tRPCpages/api/trpc/[trpc].ts is the single mount; all routers come from packages/trpc/server/routers.
  • Stripe webhookspages/api/integrations/stripepayment/webhook.ts plus the Stripe app under packages/app-store/stripepayment.
  • Calendar webhookspages/api/integrations/<provider>/webhook for Google Calendar push notifications, Office 365, etc.
  • Embeds — the embed runtime mounts via apps/web/modules/embed/ and uses packages/embeds/embed-core. The published JS bundle lives at apps/web/public/embed/embed.js.
  • Sentryinstrumentation.ts + sentry.*.config.ts.
  • Trigger.devapps/web/trigger.version.ts plus jobs declared in packages/features/trigger.config.ts.

Entry points for modification

  • Adding a new authenticated page: create apps/web/app/(use-page-wrapper)/(main-nav)/<route>/page.tsx, point it at a View in apps/web/modules/<route>/. Permission checks belong in page.tsx, never in layout.tsx (AGENTS.md).
  • Adding a new public route: prefer the (booking-page-wrapper) group if it is booking-related. For unauthenticated marketing-style pages, create the route under apps/web/app/ directly.
  • Adding a new API endpoint: prefer adding a tRPC procedure in packages/trpc/server/routers/.... Only fall back to a Pages-Router handler under apps/web/pages/api/ for webhooks or callbacks that need raw HTTP semantics.
  • Changing rewrites/headers: edit apps/web/next.config.ts and apps/web/pagesAndRewritePaths.ts. The proxy logic in apps/web/proxy.ts stays in sync with these.

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

Web – Cal.com wiki | Factory