Hotel Reservation System Low-Level Design

Requirements

  • Search available rooms for a date range (check-in, check-out, guests, room type)
  • Book a room: prevent double-booking the same room for overlapping dates
  • Manage room inventory: hotel admins can add/remove rooms and configure pricing
  • Handle cancellations with configurable cancellation policies
  • 10K hotels, 1M rooms total, 100K bookings/day

Data Model

Hotel(hotel_id, name, address, city, country, lat, lng, rating, amenities[])
RoomType(room_type_id, hotel_id, name, capacity, bed_type, amenities[], base_price)
Room(room_id, hotel_id, room_type_id, room_number, floor, status ENUM(ACTIVE,MAINTENANCE))
Reservation(reservation_id, user_id, hotel_id, room_id, check_in, check_out,
            status ENUM(PENDING,CONFIRMED,CANCELLED), total_amount, created_at)
RoomPrice(room_type_id, date, price)  -- per-night pricing, overrides base_price

Query: find available rooms at Hotel H for check-in C1 and check-out C2.

SELECT r.room_id, rt.name, rp.price
FROM Room r
JOIN RoomType rt ON r.room_type_id = rt.room_type_id
LEFT JOIN RoomPrice rp ON rp.room_type_id = rt.room_type_id AND rp.date = :check_in
WHERE r.hotel_id = :hotel_id
  AND r.status = 'ACTIVE'
  AND r.room_id NOT IN (
    SELECT room_id FROM Reservation
    WHERE status IN ('PENDING', 'CONFIRMED')
      AND check_in  :check_in  -- overlapping date ranges
  )

Date overlap condition: two ranges [A,B) and [C,D) overlap iff A < D AND B > C.

Booking Flow (Preventing Double-Booking)

  1. User selects room and dates
  2. POST /reservations/hold: create Reservation with status=PENDING, expires_at=NOW()+15min
  3. User confirms and pays
  4. POST /reservations/{id}/confirm: BEGIN TRANSACTION; check no other CONFIRMED reservation overlaps (SELECT COUNT(*) … FOR UPDATE); if clean, charge payment; UPDATE status=CONFIRMED; COMMIT

The SELECT FOR UPDATE at step 4 acquires a row-level lock on the room’s reservations, preventing concurrent bookings. The hold (PENDING) at step 2 uses an INSERT with a UNIQUE constraint check to prevent creating two PENDINGs for the same room+dates simultaneously.

Availability Cache

Availability queries are read-heavy (users search many times before booking). Cache available room counts per hotel per date range in Redis: key=avail:{hotel_id}:{date}, value=hash of room_type_id → available_count. TTL=60s. Invalidate on booking and cancellation. Slight staleness (60s) is acceptable — the actual booking still validates in the DB. This reduces load on the reservation query by 90%+.

Dynamic Pricing

Hotel admins set per-night prices via the RoomPrice table. Price depends on: day of week, season, local events, current occupancy (yield management). Occupancy-based pricing: if occupancy > 80% for a date, apply a 1.2x multiplier. Computed nightly by a batch job. The active price for a room type on a date is: COALESCE(RoomPrice.price, RoomType.base_price). Cache the price in Redis with the availability data.

Cancellation Policy

Policy types: FREE_CANCELLATION (cancel anytime for full refund), PARTIAL_REFUND (50% refund if cancelled >48h before check-in), NON_REFUNDABLE. On cancellation: check policy and calculate refund amount; initiate refund via payment processor; UPDATE Reservation SET status=CANCELLED; add room back to available inventory (cache invalidation + DB update). Cancellation within 24h of check-in: apply the strictest policy.

Overbooking Handling

Airlines overbook intentionally; hotels may do so unintentionally. When a hotel is overbooked (more confirmed reservations than rooms): walk the guest (book them at an equivalent or better hotel, pay the difference). Track walked_reservations for SLA monitoring. Prevention: use SELECT FOR UPDATE strictly and cap pending reservations to available_rooms + 5% buffer.

Key Design Decisions

  • Overlap condition: A < D AND B > C — memorize this for availability queries
  • Two-phase booking (PENDING → CONFIRMED) with expiry gives users time to complete payment
  • SELECT FOR UPDATE at confirm time prevents the race condition between two users booking the same room
  • Per-night RoomPrice table enables dynamic pricing without schema changes

Airbnb system design is the canonical hotel reservation interview topic. See common questions for Airbnb interview: hotel reservation and availability system design.

Amazon system design covers booking and reservation systems. Review design patterns for Amazon interview: reservation and booking system design.

Stripe system design covers payment flows for reservation systems. See design patterns for Stripe interview: payment and reservation system design.

Scroll to Top