Skip to content
System design course
Ch.4 · Designing real systems·concept ·8 min read

Designing a flight booking system

Search flights across airlines and book seats without double-selling — complex multi-leg search, volatile inventory/pricing, and a hold-and-confirm reservation.


The problem

Design a flight booking system (an OTA like Expedia, or an airline’s): search flights by route/date across many airlines, show fares, and book a seat without double-selling it. The challenges: complex search (multi-leg itineraries), volatile third-party inventory/pricing, and a consistent reservation that can’t oversell.

Step 1 — Requirements

Functional: search flights (origin, destination, dates, passengers; one-way/round/ multi-city); show fares/availability; select + book seats; payment; manage bookings (PNR); cancellations.

Non-functional: low-latency search over a huge combination space, fresh availability/pricing (changes constantly), strong consistency for booking (no double-sold seats), available, scalable (read-heavy search ≫ bookings).

Step 2 — Search (the hard read problem)

Flight search explodes combinatorially — multi-leg itineraries, connections, date flexibility, multiple airlines:

  • Inventory source — airlines/GDS (Global Distribution Systems like Amadeus/ Sabre) hold the real availability + fares. An OTA queries them (slow, rate-limited, paid per query).
  • Caching — cache fare/availability results aggressively (with short TTLs, since they change) to avoid hammering the GDS on every search; pre-cache popular routes.
  • Itinerary construction — build connecting itineraries (graph search over flights/ airports within time constraints) and rank by price/duration/stops.

So search = cached GDS data + itinerary assembly + ranking. It’s read-heavy and latency-sensitive.

Step 3 — The freshness problem

Cached availability/price may be stale by booking time (someone else booked, fare changed). So:

  • Re-validate at booking — re-query the airline/GDS for the exact fare + seat right before reserving; the cached search result is a candidate, not a guarantee.
  • Show a clear “price/availability confirmed at checkout” UX — fares can change between search and book.

Step 4 — Booking without overselling (consistency core)

Reserve seats with a hold-and-confirm flow against the airline’s inventory (the seat count is a scarce, strongly-consistent resource):

select itinerary → re-validate fare/availability → HOLD seats (temporary lock, minutes)
→ take payment → CONFIRM → issue PNR/ticket  (payment fails / hold expires → release)

The hold (lease) reserves seats during checkout; the airline’s inventory system (or your mirror with a unique constraint per seat) enforces no-double-sell — the Airbnb pattern, across a third-party. Booking is CP.

Step 5 — Architecture

search → cache (fares/availability) ⇄ GDS/airline APIs → itinerary builder → ranked results
booking → re-validate → hold (lease) → payment → confirm (PNR) → ticketing
manage → PNR store; cancellations/refunds (saga with the airline)

Step 6 — PNR and post-booking

A confirmed booking is a PNR (Passenger Name Record) stored durably; changes/cancellations are a saga coordinating with the airline (refund + release seats), idempotent and reconciled (payment lessons).

Trade-offs to raise

  • Cache search (fast, may be stale) vs live GDS per search (fresh, slow/costly). Cache with short TTLs + re-validate at booking.
  • Hold/lease (good UX, seats briefly locked) vs book-on-click.
  • Search latency vs coverage — more airlines/combinations = richer but slower; parallel fan-out + caching.
  • CP booking over availability.

The interview cue

“Search assembles itineraries from cached GDS availability/fares (short TTLs, pre-cache hot routes) and ranks them; because fares/seats are volatile, re-validate at booking and use a hold → pay → confirm flow against the airline’s inventory (no double-sell — CP), issuing a PNR; cancellations are a saga with the airline.” Cached complex search + freshness re-validation + CP hold-and-confirm is the answer; implementation next.