Bookings, reservations and availability
Designing reservation systems that never double-book: modelling availability for rooms, rentals, appointments and seats, holds with expiry, preventing overlaps with constraints and locks, time zones, overbooking strategies, searching availability, and syncing with external calendars.
Reading is half of it. See this used in a real interview: walk through Design Airbnb →
Hotels, vacation rentals, restaurants, doctors' appointments, rental cars and event seats all share one problem: a resource can be used by only one customer for a given time, many customers try to book at once, and a double booking is a real-world disaster (two families at one beach house). Booking questions test data modelling for time ranges, concurrency control and the holds that make checkout work.
Modelling availability
Two common models:
| Model | How | Good for |
|---|---|---|
| Per-slot rows | one row per resource per night or time slot, with status | hotels by night, appointments in fixed slots, seats |
| Ranges | one row per booking with start and end | flexible durations, rentals by the hour |
Per-slot rows make concurrency simple (claim each night's row) and searches easy, at the cost of many rows (a listing for a year has 365). Ranges are compact but need overlap checks.
For hotels with many identical rooms, track counts per room type per night rather than individual rooms, and assign specific rooms at check-in.
Preventing double bookings
The guarantee must live in the database, not in application code that checks then writes:
- Per-slot: a conditional update per night (
UPDATE nights SET booking_id = ? WHERE listing = ? AND night = ? AND booking_id IS NULL), all in one transaction; if any night fails, roll back. - Ranges in Postgres: an exclusion constraint on (resource, time range) using a range type rejects overlapping bookings atomically.
- Counts:
UPDATE inventory SET booked = booked + 1 WHERE type = ? AND night = ? AND booked < capacity. - Unique constraints on (resource, slot) for fixed slots.
See transactions and isolation. Distributed locks are rarely necessary when the database can do this. See distributed locks and leases.
Holds during checkout
Payment and form-filling take minutes. Without a hold, someone else books in the meantime; with an indefinite hold, abandoned checkouts block inventory. Use holds with expiry:
- On "reserve", create a booking in
heldstate withexpires_at(for example 10 minutes), claiming the slots. - On payment success, move to
confirmed. - On expiry, a background job (or a filter at read time) releases the hold.
Count held slots as unavailable in searches, or show "someone is booking this". See inventory and flash sales and delayed jobs.
Payment and booking together
Booking and payment span systems, so use a saga: hold the slots, authorise the payment, confirm the booking, then capture the payment; on failure, release the hold and void the authorisation. Idempotency keys prevent duplicate bookings when clients retry. See distributed transactions and idempotency and payments and ledgers.
Searching availability
"Places in Lisbon for 3 to 7 June for 4 guests" must check availability across thousands of listings fast:
- A search index (Elasticsearch) handles location, price and amenities; availability is either stored in the index (updated on every booking, slightly stale) or checked in a second step against the availability store for the top results.
- Precomputed availability bitmaps per listing (one bit per night) make range checks quick.
- Final availability is always re-checked at booking time; search can be slightly stale, booking cannot. See Design Airbnb.
Time and calendars
- Store times in UTC plus the resource's time zone; nights and check-in times are local concepts.
- Daylight saving changes affect hourly bookings.
- Sync with external calendars (other booking sites, hosts' personal calendars) via iCal feeds or APIs; sync is delayed, so double bookings across platforms are possible and need a resolution process. Channel managers exist to centralise this for hotels.
Overbooking
Airlines and hotels deliberately overbook based on no-show rates to maximise use, accepting that sometimes a customer must be moved. It is a business decision built on the same counts (capacity × an overbooking factor), with a process for compensation. Most marketplaces with unique items (one apartment) never overbook.
Cancellations and changes
Cancellations release slots and trigger refunds according to policy; modifications (change dates) should claim the new slots before releasing the old ones, so the customer never loses both.
In the interview
Model availability per night (or with ranges and an exclusion constraint), claim slots atomically in a transaction, use expiring holds during checkout, coordinate payment with a saga and idempotency keys, keep search approximate but re-check at booking, and handle time zones explicitly. Practise with Design Airbnb and Design Ticketmaster.
Checklist
- Availability modelled as per-slot rows, counts or ranges.
- Database-enforced no-overlap: conditional updates, exclusion or unique constraints.
- Expiring holds released by a job or filtered at read.
- Saga for hold, payment and confirmation; idempotency keys.
- Approximate availability in search, exact check at booking.
- UTC plus local time zone; external calendar sync.
- Explicit cancellation, modification and overbooking policies.