Open-Source Wikis

/

Cal.com

/

Packages

/

trpc

calcom/cal.com

trpc

Purpose

packages/trpc is the type-safe API layer between the Next.js front end and Cal.diy's business logic. It mounts inside apps/web (pages/api/trpc/[trpc].ts), validates requests with Zod, looks up the user's NextAuth session, and dispatches to handlers in packages/features/<domain>/services.

Directory layout

trpc/
├── server/
│   ├── adapters/                     # Adapters for non-Next environments
│   ├── createContext.ts              # Builds the per-request context (session, prisma, ...)
│   ├── createNextApiHandler.ts       # The Pages-Router handler used by apps/web
│   ├── createNextApiHandler.test.ts
│   ├── errorFormatter.ts             # Maps thrown errors to client-friendly shapes
│   ├── errorFormatter.test.ts
│   ├── lib/                          # Shared helpers
│   ├── middlewares/                  # Auth, audit, rate-limit middlewares
│   ├── onErrorHandler.ts             # Top-level error logging
│   ├── procedures/                   # Building blocks (publicProcedure, authedProcedure, ...)
│   ├── routers/
│   │   ├── _app.ts                   # Root router that mounts everything
│   │   ├── viewer/                   # Most authenticated routes
│   │   ├── loggedInViewer/           # Authenticated routes that are user-scoped only
│   │   ├── publicViewer/             # Public-facing endpoints (booking pages)
│   │   └── features/                 # Feature flag routes
│   ├── trpc.ts                       # The tRPC instance + router/procedure factories
│   └── types.ts
├── react/                            # React-Query bindings + provider
├── components/
└── package.json

Key abstractions

Symbol File Purpose
t (the tRPC instance) packages/trpc/server/trpc.ts Calls initTRPC.context<Context>().create(...). Exports router, procedure, etc.
createContext packages/trpc/server/createContext.ts Builds { prisma, session, user, locale, req, res, sourceIp } for every request
publicProcedure packages/trpc/server/procedures/ Procedure with no auth requirement
authedProcedure packages/trpc/server/procedures/ Requires a NextAuth session
appRouter packages/trpc/server/routers/_app.ts The root router; mounts every group
createNextApiHandler packages/trpc/server/createNextApiHandler.ts The Pages-Router HTTP handler used at /api/trpc/[trpc]
errorFormatter packages/trpc/server/errorFormatter.ts Translates TRPCError and ZodError into the response envelope

Router layout

packages/trpc/server/routers/:

  • _app.ts — root router, mounts the four groups
  • viewer/ — most authenticated procedures: bookings, event types, schedules, calendars, settings, integrations, ...
  • loggedInViewer/ — additional authenticated procedures (e.g., eventTypeOrder, addNotificationsSubscription, addSecondaryEmail, connectAndJoin, markNoShow, stripeCustomer, teamsAndUserProfilesQuery, unlinkConnectedAccount)
  • publicViewer/ — endpoints callable without a session: event, markHostAsNoShow, submitRating, countryCode, checkIfUserEmailVerificationRequired, timezones
  • features/ — feature-flag-related procedures

Inside each group, individual procedures follow a consistent four-file pattern:

<action>.handler.ts        # Implementation
<action>.schema.ts         # Zod input schema
<action>.handler.test.ts   # Vitest unit test
_router.tsx                # Procedure registration

procedures/ holds shared building blocks (e.g., protectedProcedure, the audit-logging wrapper).

How it works

sequenceDiagram
    participant Browser
    participant Next as apps/web
    participant Handler as createNextApiHandler
    participant Ctx as createContext
    participant Mw as middlewares
    participant Proc as procedure handler
    participant Service as features/<domain>/services
    participant DB as Prisma

    Browser->>Next: /api/trpc/viewer.bookings.list
    Next->>Handler: HTTP request
    Handler->>Ctx: build context (session, prisma, ip)
    Handler->>Mw: auth + rate-limit
    Mw->>Proc: validated input
    Proc->>Service: orchestrate
    Service->>DB: select queries
    DB-->>Service: rows
    Service-->>Proc: domain result
    Proc-->>Handler: serialized
    Handler->>Browser: JSON response

Integration points

  • apps/web mounts the handler at apps/web/pages/api/trpc/[trpc].ts (the only place where tRPC enters the Next.js Pages Router).
  • NextAuth session is read in createContext and exposed to every procedure.
  • packages/features/<domain> owns the actual business logic; tRPC handlers stay thin.
  • packages/platform/libraries re-exports tRPC procedures for consumption from apps/api/v2.
  • React — the React-Query-flavored client lives in packages/trpc/react. Consumers call trpc.viewer.bookings.list.useQuery({...}).

Conventions

  • Every router file is named _router.tsx. Consistent naming makes find-in-files trivial.
  • Throw TRPCError from handlers; throw ErrorWithCode from services. The error formatter unwraps both.
  • Input validation belongs in the per-procedure *.schema.ts Zod schema. Don't validate in the handler.
  • Procedures should be small. If a handler exceeds ~30 lines it probably belongs in a service.

Entry points for modification

  • Add a procedure: create <group>/<action>.handler.ts + <action>.schema.ts, register in <group>/_router.tsx.
  • Add a router group: create the directory and add it to routers/_app.ts.
  • Custom middleware: extend middlewares/ and add to the procedure builder in procedures/.
  • Web — mounts the router
  • features — provides the business-logic services tRPC calls
  • API overview — tRPC vs REST v2

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

trpc – Cal.com wiki | Factory