🚀 🚀 Launch Offer — Courses starting at ₹1499 (Limited Time)
CortexCookie

Hotel Reservation System

A hotel reservation system is a classic yet challenging distributed system problem. While the core user experience—searching hotels and booking rooms—appears simple, the underlying system must handle high traffic, low-latency search, strong consistency for bookings, and horizontal scalability, all while ensuring that critical failures such as overbooking never occur.

This blog presents a verbose, end-to-end system design for a hotel reservation platform, explaining requirements, entities, APIs, and the architectural decisions behind them.

Functional Requirements

Functional requirements define what the system should do from the perspective of different users.

Admin Capabilities

  • Admin can add hotels
  • Admin can add rooms under a hotel
  • Admin can update hotel details
  • Admin can update room details
  • Admin can delete hotels
  • Admin can delete rooms
  • Admin can update room prices for a given date range

These operations are relatively low frequency but must be reliable and auditable.

Customer Capabilities

  • Customer can search hotels and rooms based on:
    • Location
    • Ratings
    • Room types
    • Price range
    • Availability for selected dates
  • Customer can book hotel rooms
  • Customer can list all their bookings

Search and booking are the most critical customer-facing flows and must be fast and reliable.

Low-Priority Requirements

These features improve user experience but are not essential for the core system:

  • Hotels and rooms support amenities
  • Customers can review and rate hotels and rooms
  • Notification system (email, SMS, push notifications)
  • Hotel recommendations

These can be built as independent services and added incrementally.

Non-Functional Requirements

Non-functional requirements define how the system behaves under load, failures, and scale.

Consistency and the CAP Theorem

Different parts of the system make different trade-offs between consistency, availability, and partition tolerance.

Adding Hotels and Rooms

  • Eventual consistency is acceptable
  • New hotels or rooms may take time to appear in search results
  • Prioritizes scalability and availability

Search

  • Must have low latency
  • Must be highly available
  • Can tolerate slightly stale data
  • Uses denormalized, read-optimized data

Booking

  • Requires strong consistency
  • Must prevent overbooking
  • Availability must always be accurate

This separation allows the system to optimize each workflow independently.

Scalability

  • Must handle very high read traffic for search
  • Must scale horizontally
  • Services should be stateless wherever possible

Idempotency

  • Booking APIs must be idempotent
  • Prevents duplicate bookings due to retries or network failures
  • Achieved using idempotency keys and unique constraints

Core Entities

The system revolves around the following core entities:

Hotel

Represents a physical hotel and contains metadata such as name, address, category, amenities, and description.

Room

Belongs to a hotel and represents either a specific room or a room type. Includes capacity, pricing, and amenities.

Customer

End user of the system who can search hotels, make bookings, and leave reviews.

Admin

Manages hotels, rooms, and pricing.

Search

Logical component responsible for querying hotels and rooms efficiently.

Booking

Represents a confirmed reservation and must always remain consistent.

Payment

Handles financial transactions and integrates with external payment gateways.

API Design

Admin APIs

Clear API boundaries help maintain scalability and clarity.

Admin APIs

Create Hotel

POST /hotels

{
  "name": "Hotel Paradise",
  "category": "Luxury",
  "amenities": {},
  "address": "Goa, India",
  "owner": "Paradise Group",
  "description": "A beachside luxury hotel"
}

Create Room

POST /hotels/{hotelId}/rooms

{
  "roomNumber": "101",
  "roomType": "Deluxe",
  "amenities": {},
  "floor": 1
}

Delete Hotel


DELETE /hotels/{hotelId}

Delete Room

DELETE /hotels/{hotelId}/rooms/{roomId}

Update Hotel

PUT /hotels/{hotelId}

Update Room

PUT /hotels/{hotelId}/rooms/{roomId}

Update Room Price for a Date Range

PUT /hotels/{hotelId}/rooms/prices

{
  "room_type_id": "deluxe_101",
  "start_date": "2025-07-01",
  "end_date": "2025-07-07",
  "price": 4500
}

Pricing is time-dependent and should be modeled separately from room metadata.

Customer APIs

Search Hotels

GET /hotels
Query parameters include:

searchtext, city, price_min, price_max, number_of_rooms, number_of_guests, cursor, size

Search is optimized for read-heavy traffic and typically backed by a search engine.

Create Booking

POST /bookings

{
  "hotelId": "h123",
  "checkInDate": "2025-07-01",
  "checkOutDate": "2025-07-05",
  "roomType": "Deluxe",
  "numberOfRooms": 2,
  "guestName": "John Doe",
  "numberOfGuests": 4,
  "paymentInfo": {}
}

Booking creation must atomically:

  • Validate availability

  • Reserve rooms

  • Process payment

  • Confirm the booking

List Customer Bookings

GET /bookings?customerId={id}

Add Review

POST /reviews

{
  "booking_id": "b456",
  "hotel_id": "h123",
  "room_type_id": "deluxe_101",
  "rating": 4.5,
  "comment": "Great stay, excellent service!"
}

High Level Design

Feature Extraction

Scale Calculation

Before designing the architecture of a hotel reservation system, it is critical to estimate scale. Scale calculations help us understand expected traffic, storage requirements, and system bottlenecks. This section walks through a verbose and structured scale estimation, based on realistic assumptions for a global platform.

User Assumptions

We start by defining the size of the user base and their behavior.

  • Total registered users: 500 million
  • Daily active users (DAU): 5 million

Daily active users represent users who interact with the system on a given day and are the primary drivers of traffic.

User Activity Assumptions

Each active user performs multiple actions per day:

  • Searches: 10 searches per user per day
  • Hotel detail views: 5 hotel listing views per user per day
  • Bookings: 1 million total bookings per day (system-wide)

These actions translate directly into read and write traffic on the system.

Traffic Estimation

Queries Per Second (QPS)

QPS represents read-heavy traffic, such as search and hotel detail views.

Search QPS

  • Searches per user per day: 10
  • Daily active users: 5 million

Total searches per day:

5×106×10=50×106 searches/day5 \times 10^6 \times 10 = 50 \times 10^6 \text{ searches/day}

To convert daily traffic to per-second traffic, we assume:

1 day105 seconds1 \text{ day} \approx 10^5 \text{ seconds}

Search QPS:

50×106105500 searches/sec\frac{50 \times 10^6}{10^5} \approx 500 \text{ searches/sec}

Hotel Listing View QPS

  • Hotel detail views per user per day: 5
  • Daily active users: 5 million

Total hotel views per day:

5×106×5=25×106 views/day5 \times 10^6 \times 5 = 25 \times 10^6 \text{ views/day}

Hotel detail view QPS:

25×106105250 views/sec\frac{25 \times 10^6}{10^5} \approx 250 \text{ views/sec}

Total QPS

The system’s total read traffic is the sum of search and hotel detail views:

QPS=500+250=750 requests/secQPS = 500 + 250 = 750 \text{ requests/sec}

This number is critical for designing:

  • Search services
  • Caching layers
  • Load balancers

Transactions Per Second (TPS)

TPS represents write-heavy, strongly consistent operations, primarily bookings.

Booking TPS

  • Total bookings per day: 1 million

Booking TPS:

10610510 bookings/sec\frac{10^6}{10^5} \approx 10 \text{ bookings/sec}

So:

TPS=10TPS = 10

Even though TPS is much lower than QPS, booking operations are far more complex and require:

  • Strong consistency
  • Inventory locking
  • Idempotency
  • Payment coordination

Storage Estimation

Storage calculations help determine database sizing, replication strategies, and cost.

User Storage

  • Total users: 500 million
  • Storage per user: 1 KB

Total user storage:

500×106×1 KB=500 GB500 \times 10^6 \times 1 \text{ KB} = 500 \text{ GB}

This includes:

  • Profile data
  • Preferences
  • Authentication metadata

Booking Storage

  • Bookings per day: 1 million
  • Bookings per year:
1×106×365=365×1061 \times 10^6 \times 365 = 365 \times 10^6
  • Bookings over 5 years:
365×106×52×109 bookings365 \times 10^6 \times 5 \approx 2 \times 10^9 \text{ bookings}
  • Storage per booking: 2 KB

Total booking storage:

2×109×2 KB=4 TB2 \times 10^9 \times 2 \text{ KB} = 4 \text{ TB}

Bookings form one of the largest and most critical datasets and often require long-term retention.

Hotel and Listing Storage

  • Total hotel listings: 10 million
Metadata Storage
  • Average metadata size per listing: 5 KB

Total listing metadata storage:

10×106×5 KB=50 GB10 \times 10^6 \times 5 \text{ KB} = 50 \text{ GB}
Image Storage
  • Average photos per listing: 10
  • Average photo size: 1 MB

Total image storage:

10×106×10×1 MB=100 TB10 \times 10^6 \times 10 \times 1 \text{ MB} = 100 \text{ TB}

Images dominate storage requirements and are typically stored in:

  • Object storage (S3-like systems)
  • CDN-backed infrastructure

Deep Dive: Data Model

  • Hotel – Stores core property information such as name, description, rating, category, ownership, and address reference.

  • Address – Captures normalized location details including city, state, country, and geo-coordinates for mapping and proximity queries.

  • Room_Type – Defines logical room categories (e.g., Deluxe, Suite) with shared attributes like capacity and bed configuration.

  • Room – Represents physical room inventory mapped to a room type for granular tracking and management.

  • Amenities – Maintains a master catalog of facilities or features that can be associated with hotels or room types.

  • Hotel_Amenities – Maps amenities to hotels, enabling flexible many-to-many relationships without schema changes.

  • Room_Amenities – Associates amenities with room types, allowing different room categories to expose distinct features.

  • Rates – Stores date-aware pricing, discounts, currency, and refund policies to support dynamic pricing strategies.

Feature Extraction

Deep Dive: Admin Flow

Hotel administrators interact with the system through privileged workflows that modify core business data. These operations are write-heavy, consistency-sensitive, and directly influence downstream systems such as search and pricing.

Typical admin actions include:

  • Creating and updating hotels
  • Managing room types and rooms
  • Updating dynamic room rates

All admin requests enter through the API Gateway:

Admin → API Gateway → Hotel Service

The API Gateway enforces authentication, authorization, and request validation, ensuring only authorized owners or operators can modify hotel data.

The Hotel Service acts as the primary orchestration layer for administrative operations. It validates business rules, persists changes to the primary SQL database, and coordinates with specialized services when required.

The static files like hotel/room images can be stored in object storage and CDN for faster access.

Room prices for dates and room availability can also be updated by Admin using Hotel Service.

After successful writes, domain events are published to the Inbound Topic so that Downstream consumers can consume from that:

Hotel Service / Rate Service → Inbound Topic

Feature Extraction

This event-driven design ensures that write operations remain fast while allowing downstream search and read models to remain eventually consistent.

Admin flows prioritize strong consistency at the database level, while propagation to read-optimized systems (search, cache) occurs asynchronously for scalability and fault isolation.

When we need to scale, for pricing updates, the Hotel Service can delegate to the Rate Service, which owns pricing logic and writes to the rates table. This separation isolates frequently changing rate data from relatively static hotel metadata.

Also room availability can be handled by a separate inventory services when we will have complex reservation logic or we want to support overbooking etc.

Feature Extraction

Deep Dive: Search in a Hotel Reservation System

Search is the most frequently used and latency-sensitive component of a hotel reservation platform. User perception of system quality is heavily influenced by search speed, relevance, and flexibility.

Hotel searches are intent-rich and multi-dimensional. Queries often combine multiple constraints:

  • Location → "near MG Road"
  • Price → "under 5000"
  • Room Type → "luxury suite"
  • Distance → "within 5km"
  • Amenities → "rooftop pool"

Example queries:

  • "hotels near MG Road with rooftop pool"
  • "luxury suite in Goa under 5000"
  • "hotels within 5km of Bangalore airport"

Search Flow

Search uses eventual consistency:

  • Slightly stale data is acceptable
  • Improves scalability & availability
  • Booking correctness unaffected

A typical search request follows this path: User → Search Page → API Gateway → Search Service → Elasticsearch

  1. User submits query via Search Page (web/mobile)
  2. Request passes through API Gateway
  3. Gateway routes to Search Service
  4. Search Service queries Elasticsearch
  5. Ranked results returned to client

The Search Page acts as the client entry point, capturing user queries and filters such as location, price range, room type, and amenities. It remains intentionally thin, delegating all processing to backend services.

The API Gateway serves as the centralized access layer. It handles authentication, request validation, rate limiting, and routes traffic to the appropriate backend services. This prevents clients from being tightly coupled to internal components.

The Search Service is responsible for interpreting user intent and executing search logic. Its duties include parsing queries, extracting structured filters, constructing Elasticsearch queries, ranking results, and shaping responses for the UI. Importantly, it does not query the primary SQL database.

The Elasticsearch datastore is optimized for search workloads. Hotel and room data is denormalized and indexed to support full-text search, filtering, and geo-spatial queries with low latency. This design avoids expensive joins and reduces query time.

Feature Extraction

Search Index Update Flow

To maintain search performance and avoid coupling with write-heavy systems, search index updates are handled asynchronously:

Hotel Service → SQL Database → Inbound Topic → Search Consumer → Elasticsearch

  • Hotel Admin performs CRUD operations via the Hotel Service
  • Hotel Service writes changes to the primary SQL Database
  • Hotel Service publishes change events to the Inbound Topic
  • Hotel Admin updates rate using Rate Service to update Rate changes (price, discounts, availability, inventory)
  • Rate Service writes updates into the primary SQL Database / Rate Store
  • Rate Service publishes a Rate Update Events to the Inbound Topic
  • Hotel Admin also updates the inventory details (room availability etc. for dates) using Inventory Service
  • Inventory Service also updates Inventory Update Events to the Inbound Topic
  • The Search Consumer subscribes to topic events
  • Search Consumer transforms and denormalizes data as needed
  • Elasticsearch search index is updated asynchronously
Feature Extraction

This design ensures:

  • No impact on write latency
  • Eventual consistency for search data
  • Traffic smoothing and replay capability
  • Loose coupling between services
  • Fault isolation between core systems and search

The Inbound Topic buffers change events, enabling traffic smoothing, retries, and failure isolation. The Search Consumer processes these events and updates Elasticsearch, ensuring eventual consistency while preserving search performance.

A CDN complements the search experience by serving static assets such as images, significantly reducing backend load and improving page rendering speed.

This component separation allows search to scale independently, maintain high availability, and deliver responses within strict latency targets.

Why Elasticsearch?

Elasticsearch is used because it supports:

  • Full-text search
  • Fast filtering
  • Geo-spatial queries
  • Horizontal scalability

Data is denormalized and indexed for low-latency reads.

Deep Dive: Hotel Booking Flow

Booking is the most consistency-critical workflow in a hotel reservation system. Unlike search, booking operations must guarantee correctness, prevent overbooking, and handle concurrent requests safely.

To achieve this, the system introduces dedicated inventory and allocation tables rather than relying solely on a booking record.

Key Supporting Tables

Each table serves a distinct responsibility in preserving correctness and scalability.

  • room_availability – Acts as the inventory control layer. It maintains the number of rooms available for a given room type on a specific date.
  • room_calendar – Tracks allocation of physical rooms per date. While availability is tracked at the room type level, real-world operations require assigning specific rooms. This separation allows precise room tracking, housekeeping workflows, and conflict prevention.
  • booking – Stores the transactional source of truth for reservations. Booking states typically follow a lifecycle such as: CREATED → CONFIRMED → COMPLETED
Feature Extraction Feature Extraction

Hotels, Rooms / Room Types, Amenities, Rates / Pricing rules, Room Availability / Inventory - All these are highly relational and strong consistency needed. Hence, we can keep these in a single database.

Not necessarily we need a separate database for bookings, as modern SQL DBs are good enough for our storage and TPS requirements. But considering future scale we can have a separate booking database if we want.

Booking Workflow

A typical booking request flows through the system as follows:

  1. User Initiates Booking
    The user selects hotel, room type, date range, and room count.
    Request is sent to the Booking Service.

  2. Availability Validation
    Booking Service queries Inventory Service for room_availability for the requested date range.
    Condition enforced:

    available_count ≥ requested_rooms

  3. Rate Validation
    Query Rate Service for the requested date range
    Determine final price (base price, discounts, currency rules)

  4. Atomic Inventory Update
    To prevent race conditions, inventory updates are executed atomically:

    UPDATE room_availability
    SET available_count = available_count - N
    WHERE available_count ≥ N;
    

    Failure indicates a concurrent booking conflict.

  5. Booking Record Creation A new entry is inserted into the booking table with status CREATED.

  6. Payment Processing

    Booking Service interacts with a Payment Service to make the actual payments (with payment informations received from User client - like card, back account etc.)

    Payment Success → booking_status changed to CONFIRMED

    Payment Failure/Timeout → booking_status changed to PAYMENT_FAILED and inventory restored

  7. Room Allocation Confirmed bookings result in entries within room_calendar, assigning physical rooms.

  8. Cancellation Handling Cancellation reverses prior operations:

    Increment room_availability Update room_calendar Update booking_status

Feature Extraction

How long should Booking Service wait for payment confirmation?

Once a booking entry is created with status CREATED, the system transitions it to PENDING_PAYMENT and waits for payment confirmation. This waiting period must be strictly time-bound to prevent indefinite inventory locking.

In practice, most booking systems use a timeout of 5–15 minutes, commonly around 10 minutes.

Why Not Wait Longer?

  • Rooms remain locked but unsold, reducing inventory utilization
  • Search results become inaccurate due to stale reservations
  • High-demand scenarios suffer from artificial scarcity

Why Not Too Short?

  • Legitimate users may fail to complete payment in time
  • Increased payment failures and poor user experience
  • Higher booking abandonment rates

If payment is not confirmed within the timeout window, the booking is automatically expired, and reserved inventory is released, ensuring system correctness and availability integrity.

Usually we create a payload in Cache (maybe Redis) with a timeout (TTL). If Payment is succeeded before that timeout, we are good. Otherwisse we need to reverse the reservation (restores the inventory back)

Feature Extraction

Deep Dive: Separate Booking View Service

A dedicated Booking View Service is often introduced to serve user-facing booking queries without impacting core transactional workflows.

Why Separate It?

  • Read / Write Isolation – Booking systems are write-heavy, while user views are read-heavy; separation prevents contention.
  • Optimized Read Models – Views can use denormalized, query-friendly structures tailored for UI needs.
  • Performance Stability – High read traffic (dashboards, history pages) does not degrade booking or payment operations.
  • Scalability – Read services can scale independently from booking logic.
  • Flexibility – Enables aggregation of data from multiple sources (booking, payment, refunds) without complicating core services.

This pattern follows the common principle of CQRS (Command Query Responsibility Segregation), improving responsiveness and system resilience.

Even if Booking View Service reads from the same Booking DB, separating it helps isolate read-heavy traffic from write-critical booking operations, protecting latency, stability, and scalability.

Feature Extraction

Archive Old Bookings

Old bookings are typically archived to reduce load on the primary database, improve query performance, and keep transactional tables small and efficient.

We can have a separate Archival Service that clears old bookings (after let's say 3 months) and put it in some archival database (cassandra might be a good choice here).

If user wants to view such old booking details, that can be fetched from archival database via booking view service.

Feature Extraction

Analytics & Notification Service

Every large scale system should have analytics and notification systems. Specially, booking notifications about the status change must be sent to the customers.

We can have one Search Topic and Booking Topic where Search and Booking Related Events can be put from Search Service and Booking Service. Analytics and Notification Service can read the events from the respective topics.

Feature Extraction

That was a free preview lesson.