Skip to main content

Design a Hotel Booking System

Build a system that handles millions of hotel listings, searches, and bookings while preventing double-bookings.

Related Concepts: Transactions, Caching, Database Scaling

Step 1: Requirements and Scope

Functional Requirements

RequirementDescription
SearchFind available hotels by location, dates, guests
View listingSee hotel details, photos, reviews, pricing
BookReserve a room for specific dates
Manage bookingView, modify, or cancel reservations
Inventory managementHotels update availability and pricing

Non-Functional Requirements

RequirementTargetRationale
Search latency< 200msUser experience
Booking consistencyNo double-bookingLegal and trust requirements
Availability99.99%Revenue-critical
Scale5M+ hotels, 1M+ bookings/dayGlobal travel market

Scale Estimation

  • Hotels: 5 million properties
  • Rooms: 50 million rooms total (10 per hotel average)
  • Daily searches: 500 million
  • Daily bookings: 1 million
  • Peak booking rate: 50 bookings/second

Step 2: High-Level Architecture

Loading diagram...

Step 3: Data Model

Core Entities

Loading diagram...

Availability Tracking

Option 1: Date Range Approach Store availability as date ranges with start and end dates per room. For example, room-1 is available from January 1 to January 15, then again from January 20 to February 1. This approach leads to complex queries and is difficult to update when bookings fragment the ranges.

Option 2: Daily Inventory (Recommended) Store one row per room per date, tracking total inventory and booked count. For example, room-1 on January 1 has 10 total rooms with 3 booked (7 available), on January 2 has 10 total with 5 booked, and on January 3 has 10 total with 10 booked (sold out). This approach uses simple queries and easy updates.

Pre-generate 365 days of availability per room. 50M rooms x 365 days = 18B rows. Partition by date.

Search Flow

Loading diagram...

Search Index Design

The Elasticsearch index for hotels contains fields for fast filtering:

  • hotel_id: Unique identifier
  • name: Hotel display name (e.g., "Grand Hotel NYC")
  • location: Latitude and longitude for geo queries
  • city: City name for location filtering
  • star_rating: Numeric rating (1-5)
  • amenities: Array of features like wifi, pool, gym
  • price_range: Minimum and maximum nightly rates
  • review_score: Average guest rating
  • room_types: Array of room options with type and maximum guests per room
ApproachMechanismAdvantagesDisadvantages
Post-filterSearch ES, then check DB for availabilitySimple searchSlow, may return no results
DenormalizeStore availability in ESFast searchSync complexity, staleness

Recommendation: Hybrid approach. Store "likely available" flag in ES (updated hourly). Post-filter top candidates against real-time inventory. Cache availability aggressively.

Step 5: Booking Flow

The Double-Booking Problem

Two users try to book the last room simultaneously. Without proper handling, both succeed.

Loading diagram...

Solution: Pessimistic Locking

Lock the inventory rows before checking:

Loading diagram...

SELECT ... FOR UPDATE locks the rows. Second transaction waits. Once first commits, second sees updated state.

Optimistic Locking Alternative

For lower contention scenarios, use version-based optimistic locking. The update increments both the booked count and version number, but only succeeds if the current version matches the expected value and inventory is available. If another transaction modified the row (changing the version), the update affects zero rows, signaling the need to retry or fail gracefully.

ApproachUse CaseTrade-off
PessimisticHigh contention (popular rooms)Blocking waits
OptimisticLow contention (most rooms)Retry overhead

Recommendation: Optimistic by default, pessimistic for hot inventory (last few rooms).

Booking Transaction

Loading diagram...

Hold inventory until payment confirms, but not indefinitely. Set a timeout (10-15 minutes).

Step 6: Inventory Management

Real-Time Updates

Loading diagram...

Update flow:

  1. Hotel system sends update
  2. Queue ensures durability
  3. Processor updates database
  4. Cache invalidated
  5. Search index updated async

Overbooking Handling

Hotels intentionally overbook, expecting cancellations. The system supports this by tracking both actual inventory (10 rooms) and an oversell limit (11 bookings allowed). Available rooms are calculated as oversell limit minus booked count. When booked count reaches 11 (even though only 10 rooms exist), availability shows zero. Hotels configure the oversell policy per room type based on historical cancellation rates.

Step 7: Pricing

Dynamic Pricing

Prices change based on:

  • Day of week (weekends cost more)
  • Season (holidays cost more)
  • Demand (surge pricing)
  • Lead time (last minute discounts)
Loading diagram...

Price Storage

Store base prices and modifiers separately. For example, a room with a base price of $100 per night might have modifiers for day of week (Saturdays at 1.2x multiplier), seasonality (December 20 through January 5 at 1.3x multiplier), and occupancy-based pricing (when above 80% occupancy at 1.15x multiplier).

The final price is calculated at query time by applying all applicable modifiers to the base price. This approach allows flexible pricing rules without storing every date and scenario permutation.

Step 8: Cancellation and Modifications

Cancellation Flow

Loading diagram...

Always release inventory back to available pool on cancellation.

Modification Handling

Modifications are effectively cancel + rebook:

  1. Lock new dates
  2. Verify availability
  3. Calculate price difference
  4. Process payment adjustment
  5. Release old dates
  6. Confirm new dates

All in one transaction to prevent inconsistencies.

Production Examples

SystemNotable Design Choice
Booking.comAggressive caching, extensive A/B testing
AirbnbRequest-to-book for some listings, instant for others
ExpediaAggregates multiple sources, complex pricing
HRSCorporate booking focus, negotiated rates

Summary: Key Design Decisions

DecisionOptionsRecommendation
Availability modelDate ranges, daily rowsDaily rows (simpler queries)
SearchSingle source, federatedES + post-filter availability
LockingPessimistic, optimisticOptimistic default, pessimistic for hot
Payment timingPre-auth, full chargePre-auth with timeout
Price storagePre-computed, calculatedBase + modifiers (flexible)