Airbnb Interview Questions | JiQuest

add

#

Airbnb

System design deep dive · HLD

Design Airbnb (listing search and booking marketplace): full high-level design.

Requirements, back-of-envelope capacity estimation, a high-level design diagram, a deeper deployment architecture diagram, sequence diagrams for search and booking, and an entity-relationship diagram for the data model - with the reasoning an interviewer expects behind every box and arrow.

7MActive listings
5,200/sPeak search QPS
0Tolerated double-bookings
Guestsearches dates Search indexgeo + date filter Booking servicere-checks availability Booking confirmedno double-book Payout ledgerhost paid post-stay calendar locked atomically

1. Clarify requirements before drawing any box

Airbnb's defining tension is that search must be fast and can tolerate slight staleness, while booking must be exactly correct and can never tolerate two guests being confirmed for the same listing on overlapping dates - those two halves need different consistency models.

Functional requirements

Geo + date-range searchFind listings in a location, available for a specific check-in/check-out range, matching filters (guests, price, amenities).
Book a listingReserve a listing for a date range; the reservation must be atomic against every other concurrent booking attempt.
Host payoutAfter a stay (or after a cancellation window), the host is paid out their share, minus platform fee, on a predictable schedule.
Listing managementHosts create/edit listings and manage their own availability calendar (blocking dates, setting prices).

Non-functional requirements

Zero double-bookingsTwo overlapping bookings for the same listing must never both succeed, even under concurrent requests.
Fast searchSearch results return in a few hundred milliseconds even with millions of listings and complex filters.
Read-heavy, write-lightSearches vastly outnumber bookings; the two paths should scale independently.
Financially auditable payoutsEvery payout must be traceable, idempotent, and reconcilable against actual bookings and refunds.
Explicitly out of scope Messaging between guest and host, review/rating systems, and dynamic pricing recommendation algorithms are called out as adjacent products rather than core requirements, so the core design stays focused on search, booking, and payout.

2. Back-of-the-envelope capacity estimation

These numbers decide how the search index must be sharded geographically, how the availability calendar is stored so 7 million listings times 365 days doesn't become billions of rows nobody can query, and why bookings need a completely different consistency treatment than search.

MetricAssumptionResulting estimate
Active listings7 million active listings globallybaseline for search index and calendar sizing
Search traffic150 million searches/day, 3x peak multiplier~1,740 searches/sec average, ~5,200/sec peak
Booking traffic2 million bookings/day, much smaller peak multiplier (bookings spread across a booking window, not bursty like search)~23 bookings/sec average, ~100/sec peak
Availability calendar rows7M listings × 365 days if stored per-day~2.5 billion day-rows - too many for a naive per-day table; favors a range-based representation instead (see ER section)
Search index size~2 KB/listing (geo, price, amenities, denormalized rating)7M × 2KB ≈ 14 GB - comfortably fits a sharded Elasticsearch cluster in memory-backed indices
Payout volume2M bookings/day × average $220/night × ~3.4 nights avg~$1.5B/day in gross booking value flowing through the payout ledger - underscores why this path must be exact, not eventually consistent
Why this matters The 75:1 gap between search QPS and booking QPS is the number that justifies two entirely separate systems: an eventually-consistent, horizontally-scaled search index that can show slightly-stale availability, backed by a small, strongly-consistent booking system that is the only place a reservation is ever actually confirmed.

3. High-level design (HLD)

The HLD names the major components and the two data flows - search and booking - without yet committing to sharding schemes, the specific consistency mechanism, or payout scheduling details.

Guest clientsearch & book Search servicegeo + date filter Booking servicestrongly consistent Search indexElasticsearch, geo-sharded Availability calendarsource of truth, exclusion lock Payment svccharge on confirm Payout ledgerhost paid post-stay CDC pipelinecalendar → search index
Application servicesSource-of-truth storeRead-optimized storeAsync / external

What each box owns

Search service and search index

Handles the read-heavy, latency-sensitive path: geo bounding box, date range, and filter matching against a denormalized, eventually-consistent copy of listing and rough availability data. It never confirms a booking - it only shows candidates that were available as of the last index update, which may be seconds stale.

Booking service and availability calendar

The only component allowed to confirm a reservation. It re-checks the actual, current availability_calendar (the source of truth, not the search index) inside a single atomic transaction, and only proceeds to payment if that specific date range is genuinely free at that instant - this re-check is what makes the eventually-consistent search index safe to use for browsing.

Payment service

Charges the guest only after the availability calendar transaction has successfully claimed the date range, never before - reversing that order would risk charging a guest for a booking that then fails to confirm due to a race with another guest.

Payout ledger and the CDC pipeline

The payout ledger schedules and records the host's share of each booking as a durable, append-only, double-entry-style record, decoupled from the booking transaction itself so payout timing (e.g. 24 hours after guest check-in) doesn't hold up booking confirmation. A change-data-capture pipeline propagates calendar changes from the source-of-truth database into the search index asynchronously, which is exactly why the search index can be stale by design.

4. Detailed architecture diagram

The architecture diagram answers how geo search is actually sharded, how the availability calendar prevents double-booking at the database level, and how payouts stay correct under cancellations and refunds - the details an interviewer checks once the HLD shape is accepted.

Edge / API layer CDN + API gateway Request routersearch vs. booking split Rate limiting / fraud checks Session / auth Search tier (geo-sharded, read replicas) Elasticsearch shard: NA Elasticsearch shard: EU Geohash-bucketed by region, cached candidate availability Booking tier (single source of truth) Booking service ×30 pods Payment service ×15 pods Postgres, sharded by listing_iddaterange + EXCLUDE constraintrejects overlapping bookings atomically CDC pipeline Debezium/Kafka Index updater seconds of lag - search briefly shows a just-booked listing Payout pipeline Payout scheduler Ledger writer idempotent, double-entry, delayed until cancellation window closes External payment rail Stripe Connect (marketplace) handles actual money movement to host bank accounts
DecisionChoiceReasoning
Search vs. booking consistencyEventually-consistent search index, strongly-consistent booking databaseSearch must scale to thousands of QPS and can tolerate showing a listing that gets booked a moment later; the booking transaction is the sole gatekeeper that actually enforces no-double-booking.
Double-booking preventionPostgres EXCLUDE constraint on (listing_id, daterange) rather than application-level lockingPushes the correctness guarantee into the database itself, which atomically rejects an overlapping insert - safer than any distributed lock the application would have to manage correctly under concurrency.
Payout timingDelayed until after the cancellation window, processed by a separate schedulerDecouples "booking confirmed" from "money moved," so a late cancellation or dispute doesn't require clawing back funds already paid out.
Search index freshnessAsynchronous CDC with seconds of lag, not synchronous dual-writeSynchronously updating the search index on every booking would tie search infrastructure health to booking latency; a brief staleness window is an acceptable, well-understood trade-off given the booking service re-validates anyway.

5. Sequence diagrams for the two critical flows

A sequence diagram is where an interviewer checks whether a candidate actually re-validates availability at booking time rather than trusting search results, and whether payment happens in the safe order relative to the calendar lock.

5.1 Geo + date-range search

Guest Search svc Search index 1. search(geo_box, checkin, checkout, guests) 2. geo filter + date-range availability filter 3. candidate listings, ranked 4. results (as-of index snapshot) Note: availability shown here is a hint, not a guarantee

The search response in step 4 is deliberately framed as a snapshot, not a promise - the index reflects the availability calendar as of whenever the CDC pipeline last synced, which could be a few seconds behind. This is why the booking flow below performs its own independent, authoritative check rather than trusting this result.

5.2 Booking a listing (atomic availability claim)

Guest Booking svc Availability calendar Payment svc Ledger 1. book(listing_id, checkin, checkout) 2. BEGIN; INSERT booking (EXCLUDE constraint) 3. no overlap - insert succeeds; COMMIT 4. charge guest for total 5. charge succeeded 6. booking confirmed 7. schedule payout entry (async, post cancellation window)

Step 2's database-level EXCLUDE constraint is the entire double-booking defense: if a second guest's request reaches step 2 for an overlapping date range before this transaction commits, that second insert is rejected by the database itself, with no need for the application to implement its own distributed lock. Step 4 charges payment only after step 3's commit succeeds - reserving the calendar before touching money means a failed or rejected booking never results in a stray charge.

6. Entity-relationship (ER) diagram and schema

The data model has to answer: how does the database itself prevent overlapping bookings without 2.5 billion per-day rows, how is a host's payout traceable back to a specific booking, and how does search stay independent of the booking system's write load.

hosts PK id BIGINT payout_acct VARCHAR verified BOOLEAN rating FLOAT listings PK id BIGINT FK host_id BIGINT geo GEOPOINT nightly_price DECIMAL max_guests INT amenities JSON availability_calendar PK id BIGINT FK listing_id BIGINT date_range DATERANGE EX (listing_id,date_range) reason ENUM bookings PK id BIGINT FK listing_id,guest_id BIGINT date_range DATERANGE total,status DECIMAL,ENUM 1N 1N listing_id (soft ref)

Key modeling decisions

date_range is a PostgreSQL DATERANGE with an EXCLUDE constraintThe database rejects any INSERT whose range overlaps an existing row for the same listing_id - correctness enforced structurally, not by application logic.
availability_calendar unifies bookings and host-blocked datesA host manually blocking dates and a guest's confirmed booking are both just rows with a reason field, so the same constraint protects against both kinds of conflict.
bookings duplicates date_range rather than joining back to the calendar rowKeeps booking history queryable and immutable even if the corresponding calendar row is later cleaned up or archived.
listings.amenities is JSON, not normalized columnsAmenity sets vary widely and change often; a flexible schema here avoids a migration every time a new amenity type is added, at the cost of needing the search index (not this table) for filtering.
Storage choiceUse whenWatch out for
Relational (Postgres) with range types for bookings/availabilityYou need an atomic, database-enforced guarantee against overlapping reservations - exactly the double-booking requirement.Sharding by listing_id means a query spanning many listings (like search) is the wrong workload for this store - that's what the search index is for.
Document/search store (Elasticsearch) for the listings search indexAccess pattern is geo + filter + rank across millions of listings at high QPS.No transactional guarantees; must never be the system that confirms a booking, only the system that suggests candidates.

7. Deep dives interviewers actually probe

How exactly do you guarantee zero double-bookings under concurrency?

The guarantee lives entirely in the database: a PostgreSQL EXCLUDE constraint using the btree_gist extension on (listing_id, date_range) makes any two overlapping ranges for the same listing mutually exclusive at the storage engine level. Two concurrent transactions both trying to insert overlapping bookings will have one succeed and one fail with a constraint violation - the losing request is told to retry against updated availability, rather than the application attempting to coordinate a distributed lock, which is slower and easier to get subtly wrong.

Why not just store one row per listing per day in the availability calendar?

At 7 million listings across a year, that's 2.5 billion rows for a mostly-available calendar where the interesting information is really just "which ranges are blocked." Storing only the blocked/booked ranges (via DATERANGE) instead of every individual day means the table's size tracks actual bookings and host blocks - tens of millions of rows - not the full space of listing-days, most of which are simply available and need no row at all.

How does the host payout ledger stay correct through cancellations and refunds?

Payout is deliberately not triggered at booking-confirmation time; a scheduler waits until the cancellation window has closed (and for stays already underway, sometimes waits until a set point after check-in) before writing a payout ledger entry. Each entry is idempotent, keyed by booking_id, so a scheduler retry or a duplicate trigger never double-pays a host, and a cancellation that happens before the scheduled payout simply removes the pending entry rather than requiring a reversal.

How does geo search stay fast across millions of listings and a flexible date range?

Listings are indexed with a geohash or S2-cell representation so a bounding-box query becomes a fast prefix/range lookup rather than a full haversine-distance scan. Date-range availability is pre-materialized into the search index as a compact per-listing bitset or blocked-ranges summary refreshed by the CDC pipeline, so filtering "available for these dates" is a cheap index-level check rather than a live join against the transactional booking database.

What happens if the CDC pipeline lags and search shows a listing that's actually just been booked?

This is an accepted, designed-for scenario, not a bug: the guest can attempt to book it, and the booking service's authoritative re-check (section 5.2, step 2) will reject the overlapping request against the real availability_calendar, returning a "no longer available" error so the guest can pick another listing. The alternative - making search synchronously consistent with every booking - would require search to share the booking database's write path, destroying the independent scalability that makes 5,200 searches/sec affordable in the first place.

8. Summary: what a strong answer covers

Clarified scope before designingJustified every number with a calculationSeparated eventually-consistent search from strongly-consistent booking Pushed the double-booking guarantee into the databaseOrdered payment after the calendar claim, not beforeDecoupled payout timing from booking confirmation
Interview tip When asked to design Airbnb, the strongest signal is explicitly naming which single component is allowed to say "this booking is confirmed" and proving every other component - including search - defers to it; candidates who try to keep search and booking availability perfectly in sync usually end up bottlenecking search on the booking database's write throughput.
No comments
Leave a Comment