A comprehensive guide to building a global accommodation booking system like Airbnb — covering geo-spatial search, availability management, booking consistency, and scaling to millions of listings worldwide.
This section provides a high-level overview of how a booking flows through the system.
Key Insight: The core challenge is combining geo-spatial search with date-range availability queries while preventing race conditions during booking.
Before designing the solution, we must understand what a vacation rental platform needs to accomplish and the constraints it operates under.
A vacation rental platform connects property hosts with travelers seeking accommodations. The system must handle complex search queries combining geography and date availability, process secure payments, and build trust through a review system — all while scaling globally across different timezones and currencies.
500M / 30 days / 86,400s × 5 (peak) ≈ 1,000 searches/second
50M / 30 days / 86,400s × 3 (peak) ≈ 60 bookings/second
7M listings × 5MB avg (photos) ≈ 35 TB media storage
Key Challenge: The system is read-heavy for search but requires strong consistency for bookings. This demands a hybrid architecture with eventual consistency for search and strong consistency for reservations.
The platform consists of multiple interconnected services, each handling specific responsibilities.
┌─────────────┐ ┌──────────────┐ ┌─────────────────┐
│ Mobile/ │────▶│ API │────▶│ Search │
│ Web App │◀────│ Gateway │◀────│ Service │
└─────────────┘ └──────────────┘ └────────┬────────┘
│
┌──────────────────────────────────────────┼──────────────┐
│ │ │
┌─────▼─────┐ ┌──────────────┐ ┌──────────▼────────┐ │
│ Listing │ │ Availability │ │ Booking │ │
│ Service │ │ Service │ │ Service │ │
└─────┬─────┘ └───────┬──────┘ └────────┬─────────┘ │
│ │ │ │
┌────▼────┐ ┌──────▼──────┐ ┌──────▼──────┐ ┌────▼────┐
│Listing │ │ Availability│ │ Payment │ │ Review │
│ DB │ │ DB │ │ Service │ │ Service │
└─────────┘ └─────────────┘ └─────────────┘ └─────────┘Handles geo-spatial queries using specialized indexes. Combines location, dates, guest count, and filters to find matching listings with sub-second response times.
Manages property information including photos, descriptions, amenities, house rules, and pricing. Handles CRUD operations and media uploads.
Maintains real-time calendar data for each listing. Tracks blocked dates, minimum stays, and pricing variations. Critical for preventing double bookings.
Orchestrates the booking flow including date locking, payment capture, escrow management, and payout processing to hosts.
Finding listings within a geographic area is fundamental to the platform. Users search by city, neighborhood, or map viewport.
Encodes latitude/longitude into a string. Nearby locations share common prefixes.
✓ Simple to implement
✓ Works with standard databases
~ Edge case issues at boundaries
Developed by Google. Projects Earth onto a cube, then subdivides into cells.
✓ No edge discontinuities
✓ Hierarchical cell structure
Used by: Google Maps, Foursquare
Hexagonal hierarchical spatial index. Uniform distance from center to edges.
✓ Equal-area hexagons
✓ Great for visualization
Used by: Uber, Lyft
Convert Location to Geo-Cells
User searches "Paris, France" → Geocode to lat/lng → Generate covering S2 cells at appropriate level
Query Geo-Index
Elasticsearch or PostgreSQL with PostGIS queries listings within the cell range
Apply Filters
Filter by price range, property type, amenities, instant book, superhost status
Check Availability
Join with availability service to filter listings available for requested date range
Rank Results
Apply ML ranking model considering relevance, quality, conversion probability
{
"listing_id": "abc123",
"location": {
"lat": 48.8566,
"lon": 2.3522
},
"geo_cell": "u09tvw", // Geohash for fast filtering
"property_type": "apartment",
"bedrooms": 2,
"bathrooms": 1,
"max_guests": 4,
"price_per_night": 150,
"amenities": ["wifi", "kitchen", "washer"],
"instant_book": true,
"superhost": true,
"rating": 4.8,
"review_count": 127
}Each listing has a calendar tracking which dates are available, blocked, or booked. This is queried millions of times during search and must be highly performant.
// Option 1: Date-per-row (simple but many rows)
CalendarDay {
listing_id: UUID
date: DATE
status: enum (available, blocked, booked)
price: DECIMAL
min_nights: INT
booking_id: UUID (nullable)
}
// Option 2: Date ranges (efficient for long blocks)
DateRange {
listing_id: UUID
start_date: DATE
end_date: DATE
status: enum
price: DECIMAL
booking_id: UUID (nullable)
}Store availability as a bitmap where each bit represents one day. A 365-bit string covers a full year.
# Day 1-8: available, booked, available...
10111010...
Bitwise AND operations check date range availability in O(1).
Cache availability in Redis with TTL matching calendar update frequency.
Key: avail:{listing_id}:{month}
Value: bitmap or date array
TTL: 5 minutes
Invalidate cache on booking or host calendar update.
Listings span multiple timezones. A booking for "January 15" means different moments in time depending on property location.
Dates stored as the local date at the property. Check-in at 3 PM property time, regardless of guest location.
Convert for display to guest. Show "Arriving Jan 15" but internally track property-local date.
The most critical challenge: ensuring two guests cannot book the same dates. Race conditions during high-demand periods require careful handling.
┌──────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
│ INITIATED│───▶│ PENDING │───▶│ CONFIRMED │───▶│ COMPLETED │
└──────────┘ └───────────┘ └───────────┘ └───────────┘
│ │ │
│ │ ▼
│ │ ┌───────────┐
│ └─────────▶│ CANCELLED │
│ └───────────┘
│ ┌───────────┐
└──────────────▶│ EXPIRED │ (Payment timeout)
└───────────┘Acquire exclusive lock on date range before allowing booking to proceed.
SELECT * FROM availability
WHERE listing_id = ? AND date BETWEEN ? AND ?
FOR UPDATE SKIP LOCKED;
✓ Guarantees consistency
~ Can cause contention under load
Read current version, attempt update with version check. Retry on conflict.
UPDATE availability
SET status = 'booked', version = version + 1
WHERE listing_id = ? AND date BETWEEN ? AND ?
AND version = ? AND status = 'available';
✓ Better concurrency
~ Requires retry logic
When a guest starts checkout, place a temporary hold on the dates:
Guest clicks "Reserve" → Create booking record with status PENDING
Mark dates as "held" with booking_id and expiration (15 minutes)
Other users see dates as unavailable during hold period
Payment succeeds → Mark as CONFIRMED; Payment fails → Release hold
Background job releases expired holds every minute
Payment in vacation rentals involves holding funds until check-in, then disbursing to hosts minus platform fees.
1. Guest submits payment during booking
2. Payment processor authorizes full amount
3. Funds captured and held in escrow
4. 24 hours after check-in: release to host
5. Platform fee deducted, remainder transferred
6. Refund logic handles cancellations by policy
Flexible
Full refund up to 24 hours before check-in
Moderate
Full refund up to 5 days before check-in
Strict
50% refund up to 1 week before, no refund after
Payment {
payment_id: UUID
booking_id: UUID
guest_id: UUID
host_id: UUID
amount_total: DECIMAL // Total charged to guest
platform_fee: DECIMAL // Platform commission
host_payout: DECIMAL // Amount to host
currency: VARCHAR(3) // ISO currency code
status: enum // authorized, captured, released, refunded
stripe_payment_id: VARCHAR // External processor reference
captured_at: TIMESTAMP
released_at: TIMESTAMP
}After filtering by location and availability, listings must be ranked to show the most relevant results first.
score = (
quality_score × 0.35 + // Rating, reviews, superhost
relevance_score × 0.30 + // Match to search criteria
conversion_score × 0.20 + // Historical booking rate
freshness_score × 0.10 + // Recency of updates
diversity_bonus × 0.05 // Variety in results
)
// Apply personalization layer
final_score = score × user_preference_multiplierML models continuously optimize weights based on booking outcomes and user engagement metrics.
Trust is essential in a marketplace where strangers share homes. The review system builds accountability for both hosts and guests.
Guest reviews Host: Accuracy, cleanliness, check-in, communication, location, value
Host reviews Guest: Communication, house rules, cleanliness
Double-blind: Reviews hidden until both submit or 14-day deadline passes
• ID verification for hosts and guests
• Review authenticity checks (must complete stay)
• Fake listing detection via photo analysis
• Suspicious booking pattern detection
• Secure messaging (no off-platform contact)
Review {
review_id: UUID
booking_id: UUID
reviewer_id: UUID // Guest or Host
reviewee_id: UUID // Host or Guest
review_type: enum // guest_to_host, host_to_guest
overall_rating: INT (1-5)
category_ratings: {
accuracy: INT,
cleanliness: INT,
communication: INT,
...
}
public_comment: TEXT
private_comment: TEXT // Only visible to platform
submitted_at: TIMESTAMP
published_at: TIMESTAMP // After both submit or deadline
}Deploy infrastructure close to users for low latency:
Partition data to distribute load and enable horizontal scaling:
Listings DB: Shard by listing_id → Each shard holds complete listing data → Geo-index points to shard location Availability DB: Shard by listing_id → Co-locate with listing data for locality → Frequent updates, needs write performance Bookings DB: Shard by booking_id → Cross-reference listing and user shards → Strong consistency required Users DB: Shard by user_id → Separate from listing data → Includes payment methods, preferences
Holiday seasons and events cause 3-5x traffic spikes:
Scale API and search servers based on request rate and latency metrics.
Queue booking requests during extreme peaks to prevent timeouts.
Pre-populate caches for popular destinations before peak periods.
Design a vacation rental platform with an AI interviewer and receive instant feedback on your approach.