Architecture

Cal.com Architecture: How the Codebase Actually Works

calcom/cal.com MIT 1 diagram
How to read this page

Symvanta parsed this repository into a code graph: every function, class, and method is a node, and every call or import between them is an edge. Everything on this page is computed from that graph at the commit shown above. The terms:

Module (or cluster)
A group of symbols that call each other far more than they call anything else. An algorithm called Louvain community detection finds these groups from the call traffic alone; nobody draws them by hand.
Modularity (the Q number)
A 0-to-1 score of how cleanly those groups separate. Higher means more call traffic stays inside its own group; scores around 0.7 and above read as clean boundaries.
Hub
The most depended-upon symbol inside one module.
Load-bearing symbols
PageRank, the algorithm Google originally used to rank web pages, run over the call graph instead: it surfaces the functions the rest of the codebase leans on hardest.
Arrows and their numbers
How many calls cross from one module into another. A heavier arrow means tighter coupling between those two parts.
Dependency cycle
File A imports B, which imports A again, sometimes through a longer loop. Cycles are not bugs, but a change inside one tends to ripple around the whole loop.
Mutually recursive symbols
Functions that call each other, usually the natural shape of parsers and tree-walking code.

Cal.com is an open-source scheduling platform built on Next.js, tRPC, and a NestJS-based public API (apps/api/v2): a monorepo covering the booking web app, a versioned REST API for platform integrations, and the calendar-provider adapters that keep a user's availability in sync across Google, Microsoft, and other calendars. Symvanta's Louvain community detection organized the codebase's 39,677 indexed symbols into 121 functional clusters (modularity Q=0.83, a clean separation of concerns for a monorepo this size). The codebase's biggest jobs are product-shaped: creating and validating bookings (BookingsService_2024_08_13.createBooking and the getTranslation-hubbed validation cluster it calls into), reading and writing a user's connected calendars (DestinationCalendarRepository.find), resolving the session and user context every request runs under (HttpError, the codebase's central error-signaling hub, anchoring a 414-symbol cluster), and managing user profiles across the platform API (UsersService.getUserMainProfile). Underneath sits a layer of shared infrastructure, HTTP request and response handling (get), database access (getDB), UI toast and modal plumbing (showToast), and calendar-provider utilities (safeStringify), that the product-shaped clusters call into constantly. Cal.com (the repository GitHub now also lists as Cal.diy) is released under the MIT License, with no separate commercial directory in the current codebase.

Module map

The diagram below shows the 10 largest of the 121 detected modules, sized by symbol count, with arrows weighted by how many calls cross between them. The largest, Session and User Management (414 symbols), sits near the center of the diagram because nearly every other cluster calls into its hub, HttpError, to raise a consistently shaped error (an event type that no longer exists, an unauthenticated request, a booking that fails validation) instead of throwing a raw exception.

calcom/cal.com module map: the 10 largest of 121 detected modules with call-weighted edges, generated by Symvanta
Module map of calcom/cal.com, generated by Symvanta. Link to this diagram Open full size

Where to start reading

These are the 12 most depended-upon symbols in the codebase, blended from the global PageRank ranking and the hub of each product-shaped module so a hub like DestinationCalendarRepository.find is guaranteed a seat next to high-traffic utility functions like get and push, not crowded out by them: start here to understand how the pieces connect.

A few of these are worth calling out individually. HttpError and get sit at the top because nearly every package, from the NestJS platform API to the Next.js web app to the calendar-provider adapters, raises or receives HTTP-shaped errors and requests through them; changing either one fans out across dozens of unrelated call sites, the kind of blast radius Symvanta's own change-impact analysis is built to trace before a change ships. DestinationCalendarRepository.find is the hub of the Calendar Management cluster: the lookup nearly every calendar-write path uses to find which of a user's connected calendars should receive a new event. getDB anchors the Data Access Layer cluster, shared by the platform API's Prisma-backed repositories and the embed SDK's local-storage helpers alike, two different meanings of "database" collapsed under one PageRank-favored name. getTranslation is the hub of the Booking and Validation cluster: booking validation pulls user-facing strings through the same i18n entry point it uses to verify booking fields, which is why the two ended up in one Louvain cluster. push anchors Booking Management, the cluster that registers a booking's calendar event and formats the outgoing notification emails. showToast belongs to UI Presentation Tools, the client-side toast and modal layer every Booker and dashboard view calls when a write action succeeds or fails. UsersService.getUserMainProfile is the platform API's entry point for resolving which of a user's linked profiles, personal or org-scoped, a request should act on. EventTypeGroupFilter.has, entries, safeStringify, and safeParse round out the list: general-purpose filtering and serialization helpers the product-shaped clusters above call into constantly when data crosses a request boundary.

Key subsystems

Session and User Management

Handles server sessions, user data retrieval, and request context creation. Its hub, HttpError, sits alongside UserRepository, buildLegacyRequest, getServerSession, and createContext, the members that resolve who is making a request and what session they carry before anything else runs. The cluster calls into get and safeStringify most heavily (20 times each), and into DestinationCalendarRepository.find and getTranslation (11 times each) whenever a resolved session needs a user's calendars or locale.

HTTP Request Handling

Manages incoming HTTP requests and error responses. Its hub, get, sits next to the http, post, and put verbs and HttpError.fromRequest, the constructor that turns a failed response back into the shared HttpError type. The cluster's heaviest outgoing edge goes to push (13 times), and it calls into showToast (10 times) to surface request failures directly in the UI.

Calendar Management

Handles retrieval and management of user calendars. Its hub, DestinationCalendarRepository.find, is joined by CalendarsService.getCalendars, SelectedCalendarRepository.findFirst, and getUsersCredentialsIncludeServiceAccountKey, the lookups that resolve which calendar and which stored credential a booking or sync operation should use. The cluster calls most heavily into push (27 times), the notification and event-registration cluster it feeds every time a calendar changes.

Data Access Layer

Manages database interactions and item retrieval. Its hub, getDB, sits beside getItem and setItem, the embed SDK's local-storage accessors, and useBookerStoreContext, the Booker's client-side state hook, a reminder that this cluster spans both the Prisma-backed server database and browser-side storage under one Louvain grouping. It calls into get most heavily (40 times), and into DestinationCalendarRepository.find (15 times) and EventTypeGroupFilter.has (13 times).

Media and Calendar Utilities

Handles video adaptation, calendar authentication, and key retrieval. Its hub, safeStringify, sits alongside getVideoAdapters, getDailyAppKeys, and the CalendarAuth.getAuthStrategy and CalendarAuth.getClient pair that resolves which calendar provider's credentials to use before a call goes out. The cluster's heaviest outgoing edge goes to push (32 times), and it calls into EventTypeGroupFilter.has, DestinationCalendarRepository.find, and getTranslation (9 times each).

Event Logging Utilities

Handles event formatting and logging operations. Its hub, EventTypeGroupFilter.has, sits next to format, withSelectedCalendars, and the Logger.formatArgsAsString and Logger.logInternal pair behind the codebase's logging calls, a combination that reflects how Louvain groups by call pattern rather than by folder. It calls most heavily into push (19 times), and into get and safeStringify (13 times each).

Canonical request flow

Cal.com's public API (apps/api/v2) exposes a versioned booking-creation endpoint at POST /v2/bookings (selected via the cal-api-version: 2024-08-13 request header); tracing relate(kind:chain) downstream from its handler gives the following flow for creating a booking.

  1. BookingsController_2024_08_13.createBooking (apps/api/v2/src/platform/bookings/2024-08-13/controllers/bookings.controller.ts:105) is the entry point, guarded by an optional API-auth check since booking creation does not require the caller to be signed in. It hands the parsed request straight to the service layer.
  2. BookingsService_2024_08_13.createBooking (services/bookings.service.ts:112) runs the validation every booking has to pass regardless of type: getBookedEventType resolves the event type being booked (falling back to getBookedEventTypeTeam for team events), EventTypeAccessService.userIsEventTypeAdminOrOwner checks permissions, checkBookingRequiresAuthenticationSetting and checkEventTypeHasHosts enforce the event type's own booking rules, and hasRequiredBookingFieldsResponses confirms the submitted form answers cover every required field.
  3. Once validation passes, createBooking dispatches to exactly one of four sibling methods depending on the booking's shape: createRegularBooking for a plain single booking, createSeatedBooking for a shared-seat event, and createRecurringBooking / createRecurringSeatedBooking for their recurring counterparts. All four route their input through InputBookingsService_2024_08_13 (createBookingRequest, or createRecurringBookingRequest for the recurring pair) and their response through a matching OutputBookingsService_2024_08_13 method; createRegularBooking and createSeatedBooking additionally look up the booking row through BookingsRepository_2024_08_13 before returning it.
  4. If any step along the way throws, ErrorsBookingsService_2024_08_13.handleBookingError, or handleEventTypeToBeBookedNotFound for the specific case of a missing event type, converts the failure into the API's standard error shape before it reaches the caller.

The four creation branches are siblings, not a chain: a single request runs exactly one of them, but all four converge on the same input and output services, which is why InputBookingsService_2024_08_13 and OutputBookingsService_2024_08_13 receive calls from all four branches while BookingsRepository_2024_08_13 receives calls from only the two non-recurring ones.

Health signals

Symvanta detected 14 dependency cycles across 121 modules (modularity Q=0.83). The largest spans 2,098 files: an import cycle that reaches across most of the apps/web application, centered on widely shared infrastructure such as the webhook notifier (WebhookNotifier.ts), the tRPC public procedure base (publicProcedure.ts), and shared email templates, which end up importing back into the pages and components that trigger them. A more contained example sits in the platform API: seven NestJS module files, event-types_2024_04_15, stripe, users, both schedules API versions, event-types-private-links, and organizations, import each other in a loop, with the edge from the 2024-04-15 event-types module back into the organizations module marked as the one to break. 6 sets of mutually recursive symbols were also detected, the largest being outputs (4 symbols): the four OutputBookingFieldValidator_2024_06_14 methods (validate, validateCustomField, validateDefaultField, validateUnknownField) that dispatch across each other while validating a booking output field. Smaller recursive pairs also appear in conferencing (video-call creation and recording lookups) and bookings (field preprocessing), each a function calling its own counterpart. A modularity Q of 0.83 indicates the 121 modules are cleanly separated overall: most call traffic stays within a module rather than crossing between them.

See your own codebase mapped like this.

Book a demo →

Auto-generated by Symvanta from the public repo calcom/cal.com at commit f004349 , licensed MIT .

Get this for your codebase →