System Design · step by step

Design Airbnb

Step 1 / 9
The numbers to beatquadtreespatial splitviewportbounded querymsgeo lookup

In the interview room

How you’d open this design in an interview

Before any boxes: agree what it must do, pin the qualities that shape everything, then build — naming each trade-off as you make it. The walkthrough above is that exact order.

Functional requirements

What it must do — agree on these before drawing a single box.

  • List a home: a host publishes a listing with photos, price and an availability calendar.
  • Search: guests query by place, date range, price and amenities, ranked for relevance — the hot path.
  • Availability: results exclude homes already taken for the requested nights.
  • Book: reserve a contiguous range of nights atomically — never double-book a home.
  • Pay & review: hold-and-capture the guest’s card on confirmation; reviews feed ranking.

Non-functional requirements

The qualities that shape the whole design — each one names the mechanism that buys it.

Heavy search never threatens the source of truth
Search reads a derived index while host writes go to the Listings DB — so a search overload or a bad reindex never endangers the booking-critical data.
“Homes near here” without a planet-wide scan
A spatial index (quadtree / geohash) buckets listings by region, turning proximity into a bounded viewport lookup over a small candidate set.
Filter by date range
A per-listing availability calendar of open/taken nights that both search filtering and the booking reserve read from.
Never double-book a home
The booking service reserves the nights in one atomic transaction, guarded by a unique (listing, night) constraint or row lock — concurrent conflicts collapse to a single winner.
Safe, retryable payments
Authorize (hold) at booking and capture on confirm, with an idempotency key so a retried charge never double-charges and the dates release if payment fails.
Search stays fresh without slowing writes
Listing and booking changes emit events; consumers reindex search and aggregate reviews asynchronously, off the write path.
Absorb read-heavy, spiky traffic
Read replicas for listings, cached popular searches and listing pages, and regional sharding — while the rare booking path stays transactional on the primary.

The trade-offs you say out loud

Senior signal isn’t the boxes — it’s naming what you gave up and why it was the right price.

A derived search indexover searching the write database directly

Running heavy search straight against the source-of-truth DB makes reads contend with listings and bookings and can’t scale on its own. A separate index lets search scale, and a search overload never threatens the writes.

A spatial indexover a lat/long B-tree

A 1-D index can’t answer 2-D proximity — nearby on one axis can be far on the other, so you still scan huge ranges. A quadtree/geohash makes “near here” a bounded region lookup.

One atomic reserveover check availability then write

A gap between check and write is the classic race: both guests see “free”, both write, someone arrives at a taken house. A unique (listing, night) constraint makes check-and-set indivisible.

Authorize-then-captureover charging immediately

Charging before the booking is confirmed means refunds, double-charges on retries and money taken for stays that never happen. Hold-then-capture unwinds cleanly, and an idempotency key makes the retried path safe.

Async reindex via eventsover synchronous reindex on the write

Reindexing and review aggregation inline make every write wait on slow index updates. These effects are eventually-consistent by nature, so an event stream keeps writes fast and search current.

What this teaches

Learn system design by building a lodging marketplace like Airbnb step by step. An interactive guide covering listings, geo search with filters, availability calendars, booking without double-booking, the payment hold-and-capture flow, reviews and reindexing, and scaling reads.

Key takeaways

  • A gateway splitting heavy search reads from rare, careful booking writes.
  • A spatial index (quadtree/geohash) makes “homes near here” a bounded query.
  • Per-listing availability calendars power both date filtering and booking.
  • Atomic, lock-guarded booking so overlapping stays can never double-book.
  • Payment hold-then-capture with idempotency keys for safe, retryable charges.
  • Event-driven reindexing and review aggregation keep search fresh asynchronously.
  • Read replicas, search caching and regional sharding scale the read-heavy load.

Concepts covered

  • What is Airbnb?
  • List and find homes
  • Geo indexing
  • Availability calendars
  • Transactional booking
  • Payment hold & capture
  • Reviews & reindexing
  • The sharp edges

Design Airbnb — read the full walkthrough as text

the same steps, decisions & trade-offs, for reading, reference & search

The big idea

What is Airbnb?

A two-sided marketplace: hosts list homes, guests search by place and dates and book a stay. The reads (search) are enormous and demand geo + availability filtering; the writes (bookings) are rare but absolutely must never double-book a home.

Build a fast, filterable search over a spatial index and availability calendars, then a transactional booking path that reserves dates atomically and holds payment. Search optimizes for scale; booking optimizes for correctness.

How to read this: We add one piece at a time, problem then fix, and the diagram grows. Hit Begin.

Step 1 · The skeleton

List and find homes

Hosts need to publish listings and guests need to find them. Even ignoring geography and dates, you need a clean split between the catalog of homes and the act of searching it.

Design decision: Guest searches massively outnumber host writes. How do you structure search vs the catalog?

The call: Search reads a derived index; writes go to the Listings DB. — The gateway routes host writes to the Listings DB and guest queries to a search service reading an index derived from it. Search scales for read traffic while writes stay simple — and a search overload never threatens the source of truth.

An API Gateway sends host writes to a Listings DB and guest queries to a Search Service that reads from it. This separation lets search scale for heavy read traffic while writes stay simple and consistent.

Search reads a copy: The search service works off an index derived from the listings data, not the write database directly. Keeping them separate means heavy search load never threatens the source of truth.

Step 2 · Search by place

Geo indexing

“Homes near this map area” is the core query, but computing distance to every listing on earth per search is impossibly slow. A normal database index on lat/long doesn’t handle 2D proximity well.

Design decision: "Homes near this map area" is the core query. How do you avoid computing distance to every listing on earth?

The call: A spatial index (quadtree / geohash) bucketed by region. — Geohashing turns 2-D coordinates into a sortable prefix; quadtrees split dense areas. Proximity search becomes a bounded lookup of listings in the viewport, then filter/rank that small set.

Build a spatial index — a quadtree or geohash — that buckets listings by region so you can fetch just the ones inside the viewport quickly, then filter and rank that small set.

Index space, not just values: Geohashing turns 2D coordinates into a sortable prefix; quadtrees recursively split dense areas. Either way, proximity search becomes a bounded lookup instead of a planet-wide scan.

Step 3 · Only what’s free

Availability calendars

Guests search by date range, so results must exclude homes already booked for those nights. Availability changes constantly as bookings happen, and it gates both search and booking.

Design decision: Guests search by date range, so results must exclude homes booked for those nights. How do you model "is it free?"

The call: A per-listing calendar of open/taken nights. — One authoritative availability calendar per listing lets search filter by the requested range and booking later reserve against the same calendar. Modeling a date range makes both filtering and the no-double-book check natural.

Keep a per-listing Availability calendar of open/taken nights. Search filters candidates by the requested range; booking will later reserve against the same calendar. One authoritative place for “is this home free?”.

Date-range inventory: Unlike a single seat, a stay spans a contiguous range of nights that must all be free. Modeling availability as a calendar makes both filtering and the no-double-book check natural.

Step 4 · Never double-book

Transactional booking

Two guests try to book the same home for overlapping dates at the same instant. Without care, both succeed — and one shows up to a taken house. This is the marketplace’s cardinal sin.

Design decision: Two guests try to book the same home for overlapping dates at the same instant. How do you guarantee only one wins?

The call: Reserve the nights in one atomic transaction (constraint / lock). — Check the range is free and mark it taken together, guarded by a unique (listing, night) constraint or row locks. Concurrent conflicting bookings collapse to exactly one winner; the other cleanly retries.

The Booking Service reserves the requested nights in a single atomic transaction: check the range is free and mark it taken together, guarded by a constraint or lock on the listing+dates. Concurrent conflicting bookings — exactly one wins.

Atomicity wins the race: Check-then-set must be one indivisible step. A unique constraint on (listing, night) or row locks on the calendar turns a race condition into a clean “one succeeds, the other retries”.

Step 5 · Take the money

Payment hold & capture

Confirming a stay involves money across two parties, and payment can fail or be retried. Charging twice, or reserving dates without securing payment, both break trust.

Design decision: Confirming a stay involves money and the payment can fail or be retried. How do you take it safely?

The call: Authorize (hold) at booking, capture on confirm, with an idempotency key. — Hold the card to secure funds while finalizing, capture on confirmation, and release the hold and the dates if it ultimately fails. An idempotency key makes the inherently retried payment path safe from double-charges.

On booking, authorize (hold) the guest’s card; on confirmation, capture it and schedule the host payout. Use an idempotency key so a retried request never double-charges, and release the hold (and the dates) if payment ultimately fails.

Hold, then capture: Separating authorization from capture lets you reserve funds while finalizing the booking, and unwind cleanly on failure. Idempotency keys make the inherently retried payment path safe.

Step 6 · Keep it fresh

Reviews & reindexing

New listings, price changes and reviews must show up in search, and ranking should reflect quality — but doing that work synchronously on the booking/listing path would slow everything down.

Design decision: New listings, price changes and reviews must reach search, and ranking should reflect quality. How, without slowing writes?

The call: Emit change events; consumers reindex and aggregate asynchronously. — Listing/booking changes flow to an event stream; consumers reindex search, roll reviews into ratings, update payouts and notify — off the request path. Writes stay fast, search stays current (eventually).

Emit listing and booking changes as events. Consumers reindex the search service, aggregate reviews into ratings, update host payouts and send notifications — all asynchronously, so the write path stays fast and search stays current.

Async keeps writes fast: Reindexing and review aggregation are eventually-consistent by nature. Pushing them off the request via an event stream decouples “record the change” from “propagate its effects”.

Step 7 · Scale the reads

The sharp edges

Search traffic dwarfs everything and spikes seasonally and by destination; popular cities create hotspots. One listings database can’t serve it all, and recomputing identical searches is wasteful.

Add read replicas for the listings data, cache popular search results and listing pages, and shard/partition by region. Pricing and ranking can be precomputed; the rare booking path stays transactional while reads scale out horizontally.

Scale reads, protect writes: Replicas and caches soak up the read-heavy search load; the small, consistency-critical booking path stays on the primary. Optimize each path for what it actually needs.

You did it

You just designed Airbnb.

  • A gateway splitting heavy search reads from rare, careful booking writes.
  • A spatial index (quadtree/geohash) makes “homes near here” a bounded query.
  • Per-listing availability calendars power both date filtering and booking.
  • Atomic, lock-guarded booking so overlapping stays can never double-book.
  • Payment hold-then-capture with idempotency keys for safe, retryable charges.
  • Event-driven reindexing and review aggregation keep search fresh asynchronously.
  • Read replicas, search caching and regional sharding scale the read-heavy load.
built to be booked, not memorized — make the calls, drop the search, run the gauntlet.
Finished this one? 0 / 62 System Designs done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.