•CASE STUDY

Calendar Service (Google Calendar)

7 min read·1,280 words·Intermediate

Asked at

8 candidate reports between Nov 2025 and Aug 2026

How to use this case study

SDE-2 / Mid

  • Explain the event and attendee tables
  • How recurring events are stored as rules
  • How a week view is loaded

SDE-3 / Senior

  • Go deeper on expanding recurrences with exceptions
  • Time zones
  • Finding free slots and conflicts
  • Invitation fan-out
  • The reminder scheduler

Staff / Principal

  • Discuss multi-device sync
  • Very large meetings
  • Room booking without double booking
  • Global deployment with users in many time zones

Problem RestatementProblem

Design a calendar service like Google Calendar. Users create events, invite others, and see their schedule in day, week and month views. Events can repeat ("every Monday at 10 AM"), attendees can accept or decline, and users get reminders before events start. People live in different time zones, and they use the calendar on several devices that must stay in sync. A common variant asks for a meeting scheduler that finds free times and prevents double-booking of rooms.

RequirementsRequirements

1.1 Functional

  • Create, edit and delete events (one-time and recurring).
  • Invite attendees. They receive invites and can respond (accept, decline, maybe).
  • View a date range (a week, a month) quickly.
  • Detect conflicts and suggest free slots for a group.
  • Reminders (e.g., 10 minutes before).
  • Share calendars (view or edit access).

1.2 Non-Functional

  • Read-heavy: people open the calendar far more often than they change it.
  • Correct times across time zones and daylight saving changes.
  • Sync across devices within a few seconds.
  • Reliable reminders: they should fire on time and only once.

1.3 Scale Estimates

  • 500 million users, 100M daily active.
  • Each user creates ~2 events/day → 200M events/day ≈ 2,300 writes/sec.
  • Views: 10 opens per user per day → 1B range queries/day ≈ 12K/sec.
  • Storage: ~1 KB per event → 200 GB/day before replication.

1.4 API Design

POST/v1/eventswith { title, start, end, timezone, rrule?, attendees[], reminders[] }
GET/v1/calendars/{id}/events?from=2026-09-21&to=2026-09-28
PATCH/v1/events/{id}?scope=this|following|all(edit one occurrence of a recurring event, or all of them)
POST/v1/events/{id}/respondwith { status: accepted }
POST/v1/freebusywith { users[], from, to } → busy blocks for each user

High-Level ArchitectureArchitecture

2.1 Overview

  • Event Service: create, edit, delete and view events.
  • Event DB: stores events and attendees (sharded by calendar ID).
  • Invite Service: when an event has attendees, it adds the event to each attendee's calendar and sends emails or notifications.
  • Free/Busy Service: answers "when are these people busy?" from a compact busy-time index.
  • Reminder Scheduler: fires reminders at the right time (a delayed job queue).
  • Sync Service: pushes changes to the user's other devices.

2.2 Architecture Diagram

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
    C["Web / Mobile clients"] --> API["API Gateway"]
    API --> ES["Event Service"]
    ES --> DB[("Event DB - sharded by calendar")]
    ES --> K[("Change events - Kafka")]
    K --> INV["Invite Service"]
    K --> FB["Free/Busy indexer"]
    K --> REM["Reminder Scheduler"]
    K --> SYNC["Sync / Push Service"]
    INV --> DB
    FB --> FBS[("Busy-time index")]
    REM --> N["Notifications"]
    SYNC --> C

Data ModelData model

CREATE TABLE events (
  event_id     UUID PRIMARY KEY,
  calendar_id  UUID,            -- owner calendar
  title        TEXT,
  start_utc    TIMESTAMP,       -- first occurrence start, stored in UTC
  end_utc      TIMESTAMP,
  timezone     TEXT,            -- e.g. "America/New_York", needed for recurrence
  rrule        TEXT,            -- e.g. "FREQ=WEEKLY;BYDAY=MO", NULL if one-time
  recur_until  TIMESTAMP,       -- last possible occurrence (or far future)
  version      INT
);
CREATE TABLE event_exceptions (   -- one changed or cancelled occurrence
  event_id UUID, original_start_utc TIMESTAMP, new_start_utc TIMESTAMP,
  new_end_utc TIMESTAMP, cancelled BOOLEAN
);
CREATE TABLE attendees (
  event_id UUID, user_id UUID, response TEXT,  -- accepted, declined, tentative
  PRIMARY KEY (event_id, user_id)
);
CREATE INDEX ON events (calendar_id, start_utc);

Recurring Events (the key idea)

We do not create one row per occurrence. "Every Monday forever" would be infinite. Instead:

  • Store the rule (an RRULE, the standard iCalendar format) plus the time zone.
  • When someone views a week, load events whose range overlaps the week (start_utc <= week_end AND recur_until >= week_start), then expand each rule into concrete times for that week only.
  • Apply exceptions: "this Monday moved to Tuesday" or "cancelled on Dec 25".
  • Editing "this and following" splits the series: end the old rule at that date and create a new rule starting from it.

Why store the time zone? "10 AM every Monday in New York" must stay at 10 AM local time even when daylight saving time changes. Expanding in the event's own time zone (then converting to UTC) keeps it correct.

Key FlowsFlows

5.1 Creating a meeting with attendees

  1. Save the event in the organizer's calendar.
  2. Publish a change event. The Invite Service links the event into each attendee's calendar (a row pointing to the same event_id) and sends invites.
  3. The Free/Busy indexer updates each attendee's busy blocks.
  4. The Reminder Scheduler schedules reminders for the next occurrence.

5.2 Finding a free slot

  1. Get busy blocks for all attendees in the range from the Free/Busy index. It stores only start/end pairs, with no titles, which also protects privacy.
  2. Merge all busy intervals (sort by start and combine overlaps), then return the gaps that are long enough and fall inside working hours.

Deep Dive A — Booking a room without double bookingDeep dive

Two people book the same conference room for 2 PM at the same moment. Whatever the UI does, the database has to make one of them lose.

Weak

Check for overlaps, then insert

Query the bookings for that room, see nothing overlapping 2–3 PM, insert the booking.

Sequence diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
sequenceDiagram
  participant A as Priya
  participant B as Sam
  participant DB as Bookings
  A->>DB: any booking for room 4, 2-3 PM?
  DB-->>A: none
  B->>DB: any booking for room 4, 2-3 PM?
  DB-->>B: none
  A->>DB: INSERT room 4, 2-3 PM
  B->>DB: INSERT room 4, 2-3 PM
  Note over DB: both meetings walk into the same room

The check and the insert are two statements, and the room is free in the window between them. This passes every test written with one user.

Good

Lock the room while booking

Take a row lock on the room (SELECT ... FOR UPDATE on a per-room row), run the overlap check and the insert inside that transaction, commit. The second booker waits, re-reads, and correctly fails.

This is correct, and it is a reasonable answer. The cost is that every booking for a room is serialised behind one lock — fine for conference rooms, painful if "room" becomes "doctor" or "court" with thousands of bookings a minute — and it depends on every code path remembering to take the lock. The next engineer who writes a bulk import will not.

Best

Let the database reject the overlap

Put the rule in the schema, as an exclusion constraint on the time range:

ALTER TABLE bookings ADD CONSTRAINT no_overlap
  EXCLUDE USING gist (
    room_id WITH =,
    tstzrange(starts_at, ends_at) WITH &&
  );

Now any insert that overlaps an existing booking for that room fails, whatever code path it came from. There is no check-then-act to race, no lock to forget, and the guarantee holds for the bulk importer and the migration script too.

Catch the constraint violation and turn it into "that room was just taken" — the error is the feature.

6.1 Reminders, sync and very large meetings

  • Reminders: store the next reminder time per event and user in a delayed queue (a Redis sorted set keyed by time, or the job scheduler). A worker fires due reminders and, for a recurring event, schedules the next occurrence. Use an idempotency key of (event, occurrence, user) so a retry never sends twice.
  • Multi-device sync: every change bumps a per-calendar sync token. Devices ask "what changed since 5812?" and get only the differences; a push tells them to ask now rather than on a timer.
  • All-company events: do not copy a 50,000-attendee event into 50,000 calendars. Store it once, have attendees reference it, and fan the invitations out asynchronously in batches.

Trade-offs & AlternativesTrade-offs

DecisionChoiceWhyAlternative
Recurring eventsStore rule + expand on readSmall storage, easy series editsStore every occurrence: simple queries, huge and hard to edit
Time storageUTC + original time zoneCorrect across DSTLocal time only: breaks for travelers and DST
Free/busySeparate busy-time indexFast group queries, privateScan full events: slower, leaks details
Device syncSync tokens + pushOnly sends changesFull reload: simple but wasteful

Common Follow-up QuestionsFollow-ups

  • "How do you show a month view fast?" Cache expanded occurrences per calendar per month, and invalidate when an event in that calendar changes.
  • "External invites (other providers)?" Send standard iCalendar (.ics) emails and accept replies by email.
  • "Privacy?" Shared calendars can be "free/busy only", "see details" or "edit". Check this on every read.

Wrap-UpWrap-up

Store events in UTC with their time zone, keep recurring events as rules with exceptions, and expand them only for the range being viewed. Use change events to drive invites, a free/busy index, reminders and device sync. Prevent room double-booking with a transactional overlap check, and keep sync efficient with sync tokens.

More Case Studies

Frequently Asked Questions

What is the Calendar Service (Google Calendar) system design question?

Calendar Service (Google Calendar) is a system design interview question asked at FAANG companies. It covers scheduling, distributed systems, storage, api design and tests your ability to design scalable, production-ready systems. InterviewSkool's breakdown walks you through requirements, API design, architecture, and trade-offs.

Which companies ask the Calendar Service (Google Calendar) question?

Flipkart, Google, LinkedIn, OpenAI, Snowflake, Uber have reportedly asked variations of this question in system design interviews. The exact wording may differ, but the core design challenges remain the same.

How should I prepare for the Calendar Service (Google Calendar) interview question?

Start with the problem statement and scale estimates, then design the high-level architecture. Focus on the core components, data model, and API design. InterviewSkool's breakdown covers the full solution with mermaid diagrams and trade-off analysis to help you prep efficiently.

What level is the Calendar Service (Google Calendar) question?

This question is suitable for SDE-2, SDE-3, and Staff engineer interviews. The level guidance on this page provides specific tips for each level — SDE-2 candidates should focus on core architecture, while Staff engineers should discuss trade-offs, monitoring, and incremental rollouts.

Practice with a Mock Interview

Apply what you learned in a live system design mock interview with InterviewSkool's AI interviewer.

Start System Design Interview →