System design sample solution

System design: design a reservation system

A step-by-step system design answer you could actually give in 60 minutes.

System design interview · Sample 60-minute answer · Not Booking.com's actual design · Independent, not affiliated with Booking.com

The system design question

Design a hotel reservation system with users and admins. Users book rooms for a date range, and admins manage rooms, prices and see their bookings.

Agree on the scope (5 minutes)

Say up front what you're covering.

We'll designWe'll skip
Guests booking a room for a date rangeSearch and availability browsing
Cancelling a bookingHow payment is processed inside
Admins managing rooms and pricesReviews and messaging
Admins seeing their bookingsLoyalty points and discounts

Then agree on what "good" means:

  • Never double-book: two guests can't get the same room for the same night, ever.
  • Safe to retry: if a guest's phone sends 'book' twice, they get one booking.
  • Fair prices: a guest pays the price they saw, even if the admin changes it a second later.
  • Admins see changes quickly: a new booking shows up in the hotel's view within seconds.

Rough numbers (5 minutes)

These are assumptions, made up but reasonable: 1 million properties, 1.5 million bookings a day, peaks at 10 times the average, about 1 KB per booking, and bookings kept for years.

~17
bookings per second, on average
~170
bookings per second at a peak
~550 GB
of bookings a year
~7B
room type and night rows
QuestionRough mathWhat it means
How many writes?1.5 million bookings ÷ 86,400 seconds × 10About 170 a second at a peak, which a well-split relational database handles fine
How much storage?1.5 million × 1 KB × 365 daysAbout 550 GB a year, so we'll split by hotel eventually
How many rows does a booking touch?One row per night of the stayUsually 1 to 7 rows, all for the same hotel

The overall design (10 minutes)

Guest or admin appbook, cancel, editBooking servicechecks and holdsReservations databaserooms per nightEvent streambooking changesAdmin views and emailssee bookings
Every booking goes through one service and one database transaction. Changes then flow out to admin views, emails and search.
  1. A guest picks a room type and dates. The app sends a booking request with a unique request ID.
  2. The booking service, in one database transaction, takes one room off the count for every night of the stay. If any night is sold out, nothing changes.
  3. The booking starts as 'held' for 10 minutes while the guest pays. If payment goes through it becomes 'confirmed'. If not, the rooms go back.
  4. Each change publishes an event, which updates the hotel's booking list, sends confirmation emails, and tells search the room count changed.
  5. Admins edit room counts and prices through the same service, so the same checks apply to them.

What the apps need to do

ActionWho does itWhat's sent
Create a bookingGuestRequest ID, hotel, room type, check-in, check-out, guests, quoted price
Cancel a bookingGuest or adminBooking ID
Set rooms or pricesHotel adminHotel, room type, nights, room count or price
List bookingsHotel adminHotel, date range, status, page

What we store and where

DataWhere it goesWhy
Rooms per room type per night (total and booked)Relational database, split by hotelTransactions keep counts correct when two people book at once
Prices per room type per nightSame database, same splitSo a booking reads prices and rooms together
BookingsSame database, same splitOne transaction covers the booking and the room counts
Admin booking listA copy built from eventsLets admins filter and page without slowing down bookings

Step 1: Never double-booking (12 minutes)

First decide what a guest books. Hotels mostly sell a room type, like 'double with a view', and assign the actual room number at check-in. So we track, for each room type and night, how many exist and how many are booked.

Booking a 3-night stay means bumping 'booked' by one on 3 rows, but only if each one is still under the total. Do it in one transaction, with each update saying 'add one only if booked is less than total'. If any of the 3 updates changes nothing, that night is full, so roll the whole thing back. The database makes the check and the change happen as one step, so two guests can't both grab the last room.

This leans on the database's guarantees, which is why we picked a relational one. It's a case where we want strong consistency over speed, and our numbers say we can afford it.

What about locking the rows first?

Locking each night's row, then checking, then updating also works. It's more steps and you have to lock rows in the same order every time, like by date, or two bookings can wait on each other forever. The 'update only if there's room' version does the same job with less to get wrong.

Step 2: Retries and payment (10 minutes)

Phones lose signal and people double-tap. If the app retries 'book', we don't want two bookings. So the app makes a unique request ID when the guest taps 'book' and sends it every time it retries. The booking table has a unique rule on that ID, so a second attempt finds the first booking and returns it. That's idempotency.

Payment can take a while and can fail. So a booking starts as 'held' with an expiry time. The rooms are taken off the count, so nobody else can grab them while the guest pays. If payment succeeds, mark it confirmed. If it fails or the hold expires, a cleanup job cancels it and puts the rooms back.

Pass the same request ID to the payment provider so a retried payment doesn't charge the card twice.

Step 3: Admins changing rooms and prices (8 minutes)

An admin might lower the number of double rooms from 10 to 6 when 8 are already booked. Don't allow that silently. Reject it, or let them lower it only to what's booked and show them which bookings they'd need to move.

Prices change all the time. The booking saves the total price at the moment it was made, so a later price change never touches existing bookings. If the price changed between the guest seeing it and tapping 'book', compare against the quoted price they sent and ask them to confirm the new one.

Admins need to see bookings, but listing and filtering shouldn't compete with guests booking. Build their list from the event stream into a separate copy they can query. It's a few seconds behind, which is fine for that screen. Only staff of that hotel can see its bookings, which comes down to checking who's logged in and what hotels they belong to.

Choices you should be able to defend

We choseInstead ofBecauseWe'd reconsider if
A relational database with transactionsA database without themOur traffic is small and correctness matters mostWrites grew far past what one split can handle, and we could accept more complexity
Booking room types, not room numbersBooking specific roomsIt's how hotels actually sell, and it's far fewer rows to checkA property sells unique units, like apartments
Holding rooms while the guest paysTaking rooms only after paymentThe guest never pays for a room that's then goneToo many holds expired and blocked real bookings
Splitting by hotelSplitting by guestA booking only ever touches one hotel, so the transaction stays on one machineMost lookups were by guest, which a separate copy can handle

What could go wrong (5 minutes)

What happensWhat we do about it
Two guests try for the last room at onceOne update wins, the other sees zero rows changed and gets 'sold out'
The app retries a bookingThe request ID matches the first one, so we return that booking
Payment never comes backThe hold expires after 10 minutes and the rooms go back on sale
The event stream falls behindBookings are still correct. Admin lists and emails just arrive late
A database split goes downBookings for those hotels fail until a standby copy takes over. Others keep working

Follow-up questions (5 minutes)

How would you support overbooking, like airlines do?

Let each room type have an allowed total above the real number, like 105% for 100 rooms. The same 'add one only if under the limit' check still works.

What if a guest wants two rooms?

Same transaction, more rows. Either both room types have space on every night or nothing changes.

How do bookings from other sites fit in?

Hotels often sell the same rooms elsewhere. Those come in through an API that does the same conditional update, and the hotel's system and ours keep counts in sync with events.

How the 60 minutes add up

MinutesWhat you're doing
0–5Agree on what you're building
5–10Rough numbers
10–20Draw the overall design
20–32Never double-booking
32–42Retries and payment
42–50Admins changing rooms and prices
50–55What could go wrong
55–60Follow-up questions

Key concepts used here

Further reading

We wrote this sample answer ourselves.

Practice Loop is independent and isn't affiliated with or endorsed by Booking.com.