Booking & Reservation System
Part of the Full Stack Developer Roadmap
In short
Two people click 'Book 6 pm' at the same second. Only one can win. A booking system is all about making that impossible to get wrong, plus handling time zones without tears.
A system for booking time slots or resources (appointments, tables, rooms) — practice for handling scheduling conflicts and time-based data correctly across the stack.

Think of it like this
The badminton court slot
The college court has one hook per hour. Whoever hangs their card on the 6 pm hook first gets it. A second card simply won't fit. Your database should work like that hook, not like a polite request.
Watch it happen
Two clicks, one slot
POST court 3, 6–7 pm
1/6Riya books court 3 for 6 to 7 pm.
The big ideas
What you need to know
Let the database guard
A 'check then insert' in code has a race. A database constraint is the only check that can't be skipped.
Store UTC, show local
Save timestamptz values and convert to the user's time zone only in the UI.
Generate slots from rules
Store opening hours and slot length, then compute free slots, instead of storing every empty slot.
Hold, then confirm
For paid bookings, hold a slot for a few minutes while payment happens, then confirm or release it.
See it in code
Walk through the code
1CREATE EXTENSION IF NOT EXISTS btree_gist;2 3CREATE TABLE bookings (4 id bigserial PRIMARY KEY,5 court_id int NOT NULL,6 user_id bigint NOT NULL,7 during tstzrange NOT NULL,8 EXCLUDE USING gist (court_id WITH =, during WITH &&)9);10 11-- 6 to 7 pm IST on 2 Nov, stored as UTC internally12INSERT INTO bookings (court_id, user_id, during)13VALUES (3, 42, tstzrange('2026-11-02 18:00+05:30', '2026-11-02 19:00+05:30'));14 15-- An overlapping insert for court 3 now fails with 23P01 (exclusion_violation),16-- which your API turns into 409 Slot taken.1/4btree_gist lets a plain integer column (court_id) take part in a gist exclusion constraint.
A Postgres exclusion constraint: no two rows for the same court may have overlapping time ranges. The database refuses double bookings, even when requests race.
Save yourself the pain
Common mistakes
Oops
Checking 'is the slot free?' with a SELECT, then inserting.
Do this instead
Two requests can both pass the SELECT. Use a unique or exclusion constraint and handle the error.
Oops
Storing '18:00' as a plain string with no date or zone.
Do this instead
Store full timestamps with time zone, and pick the zone explicitly when converting user input.
Your mission
First milestone: race-proof booking
Quick check
Your code does SELECT to check a slot is free, then INSERT. Under load, you still get double bookings. Why?
Go deeper
- 1Prevent double-booking the same slot under concurrent requests.
- 2Handle timezones correctly for both display and storage.
- 3Add email confirmations for successful bookings.
More projects at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.