Design a Ticket Booking System — Concerts, Flights, and Events
The flash sale problem#
Taylor Swift tickets go on sale. 10 million fans hit the page simultaneously. 50,000 seats available. Every seat must be sold exactly once. No double-booking, no overselling, no lost transactions.
This is why ticket booking is one of the hardest e-commerce problems.
Core requirements#
Functional:
- Browse events, view available seats
- Select seats and hold them temporarily
- Complete payment within hold window
- Receive confirmation + e-ticket
Non-functional:
- No double-booking (two people buying the same seat)
- Handle flash sales (millions of concurrent users)
- Sub-second seat availability updates
- Payment processing reliability
The hold-and-pay pattern#
The key to avoiding double-booking:
- Browse — User sees available seats (read from cache)
- Hold — User selects seat → system holds it for 10 minutes (locked)
- Pay — User completes payment within hold window
- Confirm — Payment succeeds → seat permanently booked
- Release — Payment fails or timeout → seat released back to inventory
SELECT → HOLD (10 min TTL) → PAY → CONFIRM
↓ (timeout)
RELEASE
Preventing double-booking#
Option 1: Pessimistic locking (database)#
BEGIN;
SELECT * FROM seats WHERE id = 'A15' AND status = 'available' FOR UPDATE;
UPDATE seats SET status = 'held', held_by = 'user123', held_until = NOW() + INTERVAL '10 minutes';
COMMIT;
FOR UPDATE locks the row — no other transaction can modify it. Safe but slow under high concurrency.
Option 2: Optimistic locking (version check)#
UPDATE seats SET status = 'held', version = version + 1
WHERE id = 'A15' AND status = 'available' AND version = 42;
-- Returns 0 rows if someone else got it first
No locks, but requires retry logic when conflicts occur. Better for high concurrency.
Option 3: Redis atomic operations#
SET seat:A15 user123 NX EX 600
NX = only if not exists. EX 600 = expire in 600 seconds. Atomic, fast, auto-release on timeout.
Architecture#
User → CDN (static seat map) → API Gateway
↓
Seat Availability Service → Redis (seat locks)
Booking Service → PostgreSQL (bookings)
Payment Service → Stripe
Notification Service → Email/SMS
Seat availability#
Real-time seat map needs to be fast:
- Redis stores current seat status (available/held/booked)
- WebSocket pushes status changes to connected clients
- CDN caches the venue layout (static part)
- Clients poll or subscribe for seat status changes
Queue for fairness#
During flash sales, put users in a virtual queue:
- User joins queue → gets position number
- Users admitted in batches (100 at a time)
- Admitted users have 10 minutes to select and pay
- Queue prevents server overload and is fairer than "fastest click wins"
Handling payment failures#
Payment can fail after seat is held:
- Retry — Retry payment 2-3 times
- Release — After all retries fail, release seat back
- Idempotency — Payment request has unique key to prevent double-charge
- Webhook — Stripe webhook confirms final payment status
Scaling for millions#
| Challenge | Solution |
|---|---|
| Millions hitting /seats | CDN-cached seat map + WebSocket updates |
| Race conditions | Redis NX for atomic seat holds |
| Payment spikes | Queue admission + async payment processing |
| Database bottleneck | Shard by event_id, read replicas |
| DDoS during sales | Cloudflare, rate limiting, CAPTCHA |
Seat selection strategies#
Choose-your-seat: User picks from interactive seat map. Best for concerts, theaters.
Best-available: System assigns the best remaining seats. Simpler, fewer conflicts. Best for flights.
General admission: No seat assignment. Just reduce inventory count. Simplest.
Visualize your booking architecture#
See how seat management, payment, and notification connect — try Codelit to generate an interactive diagram of a booking system.
Key takeaways#
- Hold-and-pay prevents double-booking — lock seat for 10 minutes during checkout
- Redis NX for atomic seat holds — fast, auto-expiring
- Virtual queue for flash sales — fairer than "fastest click wins"
- Idempotent payments — prevent double-charging on retry
- WebSocket for real-time seat status — users see seats disappear live
- Shard by event — each event's data is independent
Try it on Codelit
Chaos Mode
Simulate node failures and watch cascading impact across your architecture
90+ Templates
Practice with real-world architectures — Uber, Netflix, Slack, and more
Related articles
Try these templates
Uber Real-Time Location System
Handles 5M+ GPS pings per second using H3 hexagonal geospatial indexing.
6 componentsE-Commerce Checkout System
Production checkout flow with Stripe payments, inventory management, and fraud detection.
11 componentsAirbnb-like Booking Platform
Property rental marketplace with search, booking, payments, and reviews.
10 componentsBuild this architecture
Generate an interactive architecture for Design a Ticket Booking System in seconds.
Try it in Codelit →
Comments