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.jsonKey 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 groupsviewer/— 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,timezonesfeatures/— 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 registrationprocedures/ 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 responseIntegration points
apps/webmounts the handler atapps/web/pages/api/trpc/[trpc].ts(the only place where tRPC enters the Next.js Pages Router).- NextAuth session is read in
createContextand exposed to every procedure. packages/features/<domain>owns the actual business logic; tRPC handlers stay thin.packages/platform/librariesre-exports tRPC procedures for consumption fromapps/api/v2.- React — the React-Query-flavored client lives in
packages/trpc/react. Consumers calltrpc.viewer.bookings.list.useQuery({...}).
Conventions
- Every router file is named
_router.tsx. Consistent naming makes find-in-files trivial. - Throw
TRPCErrorfrom handlers; throwErrorWithCodefrom services. The error formatter unwraps both. - Input validation belongs in the per-procedure
*.schema.tsZod 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 inprocedures/.
Related pages
- 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.