Back to Articles

Cal.diy: Building Production Scheduling Infrastructure on the T3 Stack

[ View on GitHub ]

Cal.diy: Building Production Scheduling Infrastructure on the T3 Stack

Hook

With 43,577 GitHub stars, Cal.diy proves you can fork a commercial product, strip out enterprise features, and still deliver production-grade scheduling infrastructure that handles timezone chaos, calendar conflicts, and booking workflows that would make Calendly jealous.

Context

The scheduling tool market has long been dominated by SaaS platforms that make you choose between convenience and control. Calendly, Doodle, and others offer polished experiences but lock you into their infrastructure, pricing tiers, and data silos. Cal.com emerged as an 'open core' alternative—open source with a catch. Core features were free, but team management, SSO, and advanced workflows required enterprise licenses.

Cal.diy represents a different philosophy: a community fork that removes all commercial guardrails to deliver a 100% MIT-licensed scheduling platform. It's not about competing with Cal.com's hosted service; it's about giving developers complete ownership over scheduling infrastructure. If you've ever needed to embed booking logic into a product, customize availability algorithms, or simply refuse to send your calendar data to another third-party service, this is the codebase you study. Built on the T3 stack—a modern TypeScript architecture combining Next.js, tRPC, Prisma, and Tailwind—it demonstrates how far you can push type safety and developer experience in full-stack applications.

Technical Insight

Type-safe calls

Authenticate

Create booking

Check availability

Persist data

Query schedules

SQL queries

Sync events

External calendar sync

Next.js Client

tRPC API Layer

NextAuth

Booking Logic

Availability Engine

Prisma ORM

PostgreSQL

Calendar/Video Integrations

System architecture — auto-generated

Cal.diy's architecture reveals sophisticated patterns for building scheduling systems that non-trivial calendar applications require. At its core, the platform uses Turborepo to manage a monorepo structure where packages like @calcom/lib, @calcom/prisma, and @calcom/trpc provide shared functionality across multiple apps. This isn't just code organization—it's a strategy for maintaining type safety from database schema to API endpoints to frontend components.

The tRPC layer deserves particular attention. Unlike REST APIs where you manually sync TypeScript types between client and server, tRPC infers types directly from your backend procedures. Here's how Cal.diy defines a booking creation endpoint:

// packages/trpc/server/routers/viewer/bookings.tsx
export const bookingsRouter = router({
  create: authedProcedure
    .input(
      z.object({
        start: z.string().transform((val) => new Date(val)),
        end: z.string().transform((val) => new Date(val)),
        eventTypeId: z.number(),
        timeZone: z.string(),
        responses: z.record(z.any()).optional(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const { prisma, user } = ctx;
      const eventType = await prisma.eventType.findUnique({
        where: { id: input.eventTypeId },
        include: { users: true, schedule: true },
      });
      
      // Complex availability checking logic
      const isAvailable = await checkAvailability({
        eventType,
        startTime: input.start,
        endTime: input.end,
        timeZone: input.timeZone,
      });
      
      if (!isAvailable) {
        throw new TRPCError({
          code: 'CONFLICT',
          message: 'Selected time slot is no longer available',
        });
      }
      
      return createBooking({ eventType, input, user });
    }),
});

Notice the Zod validation schema in the .input() call. This provides runtime validation AND compile-time type inference. Your frontend automatically knows that eventTypeId must be a number and start transforms into a Date object. No manual type definitions, no sync headaches.

The availability calculation engine showcases the real complexity of scheduling systems. Cal.diy maintains user schedules as a series of availability rules (working hours, date overrides, buffer times) stored in Prisma models. When checking if a time slot works, the system must:

  1. Query all users associated with the event type
  2. Load their individual schedules and timezone preferences
  3. Convert the requested booking time into each user's local timezone
  4. Check for calendar conflicts via integrated providers (Google Calendar, Outlook)
  5. Apply buffer times before/after existing bookings
  6. Respect minimum notice periods and date ranges

This multi-dimensional constraint solving happens in packages/lib/availability.ts, where functions like getAvailableSlots() generate bookable windows by intersecting all users' availability. The code leverages Luxon for timezone math—a critical choice since JavaScript's native Date object handles timezones poorly.

Prisma's role extends beyond simple ORM duties. Cal.diy uses Prisma's middleware system to implement soft deletes, audit logging, and automatic timestamp updates. The schema defines 50+ models spanning users, bookings, event types, webhooks, payments, and integrations. Relationships use Prisma's relation mode to maintain referential integrity even with databases like PlanetScale that don't support foreign keys at the database level.

The integration architecture deserves study. Calendar providers (Google, Outlook, Apple Calendar) implement a common interface defined in packages/app-store/, allowing the core booking logic to remain provider-agnostic. When a booking is created, the system dispatches calendar events to all relevant providers through a plugin system. Each integration runs in isolation, so if Google Calendar sync fails, it doesn't break Outlook synchronization. This resilience comes from treating integrations as eventual consistency problems rather than transactional requirements.

Development experience gets first-class treatment through yarn dx, which spins up PostgreSQL in Docker, runs Prisma migrations, seeds test data (including pre-configured users and event types), and launches the Next.js dev server. Within minutes, you're testing bookings against a realistic database. This quick-start capability matters because complex codebases often have setup friction that kills contributor momentum.

Gotcha

Cal.diy ships with a prominent warning: 'For personal use only, not ready for production.' This isn't false modesty—the fork explicitly removes enterprise features that production deployments typically require. You won't find team management beyond basic user associations, no SAML/SSO integration, no workflow automation (like automated reminders or approval chains), and analytics are rudimentary at best. If you're building a scheduling tool for a company with multiple departments, compliance requirements, or audit logging needs, you'll immediately hit these limitations.

Self-hosting complexity is the second major gotcha. Unlike managed platforms, you're responsible for PostgreSQL administration, application scaling, SSL certificate management, email delivery (SMTP configuration), and security updates. The Docker setup helps development but production deployments require expertise with containers, reverse proxies, and database backups. Calendar synchronization breaks silently if OAuth credentials expire, and debugging webhook failures from payment processors requires reading server logs. There's no dashboard showing integration health. The community Discord offers help, but you won't find commercial support contracts or guaranteed response times. If your scheduling system goes down at 2 AM, you're fixing it yourself.

Verdict

Use Cal.diy if you're a developer or small team needing complete control over scheduling infrastructure without license restrictions. It's ideal when you want to embed booking logic into a larger application, customize availability algorithms beyond what SaaS tools allow, or require data sovereignty that rules out third-party services. The codebase also serves as an educational resource—if you're learning the T3 stack or building your own scheduling features, studying Cal.diy's implementation of timezone handling, tRPC patterns, and Prisma relationships provides production-tested examples. Skip it if you lack server administration experience, need enterprise features like SSO or team hierarchies, want a managed solution with guaranteed uptime, or require commercial support. In those scenarios, pay for hosted Cal.com or use Calendly. Also skip it if your project timeline is measured in weeks rather than months—setup and customization require meaningful time investment, and you'll spend more time operating infrastructure than building features.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/data-knowledge/calcom-cal-diy.svg)](https://starlog.is/api/badge-click/data-knowledge/calcom-cal-diy)