Design Airbnb

HardE-Commerce & PaymentsGeo SearchAvailability CalendarBooking ConsistencySearch Ranking

Problem

Design a marketplace where hosts list homes and guests book them for a range of nights. Hosts create listings with photos, a nightly price, and an availability calendar. Guests search by location, dates, and number of guests, and see only listings that are free for every night they want. A guest books a listing for a date range and pays, and two bookings must never overlap. The platform has 7 million active listings, 100 million searches per day, and about 2 million bookings per day.

  • Do bookings confirm instantly, or does the host approve each request?
  • Can prices vary per night (weekends, seasons), and who sets them?
  • When is the guest charged: at booking, or closer to check-in?
  • What filters must search support beyond location, dates, and guests: price, amenities, property type?
  • Should search results be personalized or just ranked by relevance and quality?
  • Do we need messaging between guest and host and reviews after a stay?

Items in bold are existing requirements. The rest are suggestions. Confirm with the interviewer whether they are relevant first.

  • Hosts create and edit listings with location, photos, nightly price, and capacity.
  • Hosts manage a per-night availability calendar.
  • Guests search by location, check-in and check-out dates, and guest count, seeing only available listings.
  • Guests book a listing for a date range and pay; overlapping bookings are impossible.
  • Support instant book and request-to-book flows.
  • Guests and hosts can cancel according to the listing's cancellation policy.
  • Guests and hosts leave reviews after a completed stay.

Items in bold are existing requirements. The rest are suggestions. Confirm with the interviewer whether they are relevant first.

  • 100 million searches per day: about 1,200 per second on average and 5,000 at peak.
  • 2 million bookings per day, about 25 per second on average.
  • Search latency under 400 ms at p99; slightly stale availability in search is acceptable.
  • Booking must be strongly consistent: the final availability check and the write happen atomically.
  • Calendar storage: 7 million listings times 365 future nights is about 2.5 billion listing-night rows, roughly 100 GB.
  • Photos: about 25 photos per listing at 500 KB in several sizes is roughly 200 TB in object storage behind a CDN.

Listing details and photos live in a listing service backed by a relational database and a CDN, while a search index holds a denormalized copy of each listing with a geo point and a compact availability bitmap. Search filters by geography and availability in the index, then ranks results. Bookings go through a booking service that atomically checks and claims every night in the range against the authoritative calendar store, and changes flow back to the search index through a change stream.

Loading diagram...

Host creates a listing. The host app uploads photos directly to object storage with presigned URLs, then sends listing details to the listing service. The listing row and its initial calendar are written, and the change stream carries the update to the search indexer, which builds a search document within seconds.

Guest searches. The guest sends GET /search?lat=&lng=&radius=&checkIn=&checkOut=&guests=. The search service converts the dates to a bit mask over nights and queries the index with a geo filter, a capacity filter, and a check that none of the requested nights are blocked. The ranking service reorders the top few hundred candidates by quality, price, and conversion signals, and the first page is returned with photo URLs served from the CDN.

Guest books. The guest selects a listing and sends POST /bookings with the date range and an idempotency key. The booking service opens a transaction, locks the calendar rows for that listing and those nights, verifies every night is available, marks them booked with the booking id, and inserts the booking. It then authorizes payment. If authorization fails, a compensating transaction releases the nights. The calendar change flows to the search index so the listing stops appearing for those dates.

Answers the core query: available listings near a place, for these dates, for this many guests, ranked well.

  • Elasticsearch or OpenSearch with geo_point fields.
  • A per-listing availability bitmap of 365 bits stored in the document for the next year.

Diagram

Loading diagram...

API

  • GET /search?lat=&lng=&radius=&checkIn=&checkOut=&guests=&minPrice=&maxPrice=&cursor= returns listing cards and a cursor.

Scalability

The index is sharded by geographic region so a city search hits one or a few shards. Replicas absorb the 5,000 searches per second peak, and popular map tiles are cached for a short time.

Tradeoffs

Storing availability in the search document means search can be a few seconds stale, and a guest may occasionally click a listing that was just booked. The booking service catches this with an authoritative check. The alternative, joining against the calendar database at query time for thousands of candidates, would make search far slower and couple it to the booking path.

Creates, confirms, and cancels bookings, and is the only writer of booked nights.

  • Stateless service on PostgreSQL, sharded by listing_id.

API

  • POST /bookings with Idempotency-Key and { listingId, checkIn, checkOut, guests } returns { bookingId, status, total }.
  • POST /bookings/:id/cancel returns the refund amount.
  • POST /bookings/:id/approve for request-to-book listings (host only).

Data Model

  • bookings(id, listing_id, guest_id, check_in, check_out, status, total_minor, payment_id, idempotency_key UNIQUE)

Scalability

Bookings are low volume (about 25 per second) and every transaction touches one listing, so sharding by listing keeps transactions on a single node with negligible contention.

Tradeoffs

Locking the specific night rows with SELECT ... FOR UPDATE is chosen over a single lock per listing, so a host's calendar edits for next summer do not block a booking for next week. An exclusion constraint on a date range column is an equally valid alternative in PostgreSQL. Payment is authorized after the nights are claimed, with a short hold, rather than before, so a guest is never charged for a stay that turned out to be unavailable.

Authoritative per-night availability and price for every listing.

  • PostgreSQL, colocated with bookings on the same shard key.

Data Model

  • listing_nights(listing_id, night DATE, status, price_minor, booking_id) with primary key (listing_id, night), where status is available, blocked, or booked.

Scalability

About 2.5 billion rows across shards by listing_id. Nights in the past are archived monthly, keeping the active table to roughly one year ahead.

Tradeoffs

One row per night is simpler to lock and price than storing date ranges, and makes per-night pricing natural. The cost is more rows, which is acceptable at about 100 GB.

Stores listing content: title, description, amenities, location, house rules, and photo references.

  • PostgreSQL for listing data; S3-style object storage plus a CDN for photos, resized into several sizes by an async image pipeline.

API

  • POST /listings, PATCH /listings/:id, GET /listings/:id.
  • POST /listings/:id/photos returns presigned upload URLs.

Scalability

Listing reads are heavily cached because content changes rarely. Writes are tiny in volume compared to reads.

Tradeoffs

Uploading photos directly to object storage keeps large payloads off the API servers. The listing database is not the search store; a change stream feeds the index, accepting a few seconds of lag in exchange for a search system optimized purely for reads.

Reorders search candidates to show the listings most likely to be booked and enjoyed.

  • Gradient boosted trees served in process, trained offline on search and booking logs.

Scalability

Ranking runs only on the top few hundred candidates per query, so cost per search is bounded regardless of how many listings match.

Tradeoffs

A two-stage design (cheap filtering in the index, then a model on a short list) is chosen over ranking inside the index, because it lets the ranking model use features such as guest history that do not belong in the search document.

Related questions