Design a Ticketing System
Table of Contents + −
When tickets for a big concert go on sale, millions of fans rush in for a few thousand seats. And here’s the twist that makes ticketing harder than a normal sale: seats are specific. Two people must never end up with the same seat 14F. Plus, a buyer needs a few minutes to pay, and that seat must be held just for them during checkout. Let’s design a system that gets this right.
🎯 What the System Does
A ticketing system needs to:
- Show which seats are available for an event.
- Let a user pick and reserve specific seats.
- Hold those seats while the user pays (a few minutes).
- Confirm the booking after payment, or release the seats if they don’t pay in time.
- Never let two people book the same seat.
That “hold during checkout” step is what sets ticketing apart. Let’s give it real attention.
📋 Requirements
Functional (what it must do):
- Browse events and see available seats.
- Reserve specific seats, hold them during payment, then confirm.
- Release held seats if payment doesn’t finish in time.
Non-functional (how well it must do it):
- Correctness: never double-book a seat. The top rule.
- Handle rushes: survive a sudden flood when popular tickets drop.
- Fairness: held seats shouldn’t be lockable forever by someone who walks away.
The unique challenge: a temporary hold
Unlike a plain sale, ticketing must hold a specific seat for one user while they pay, then either confirm it or give it back. Designing that hold-and-timeout is the heart of this problem.
🪑 Seat States
The clean way to think about a seat is as having three states. This makes the whole design click:
- Available: anyone can pick it.
- Held: reserved for one user during checkout, with a timer. Others can’t take it.
- Booked: paid for and confirmed. It’s theirs.
Reading that: a seat moves from available to held when someone reserves it, then either to booked if they pay, or back to available if their timer runs out. That timeout is what stops seats from being locked forever.
🔒 Preventing Double-Booking
Here’s the core danger. Two users both try to grab seat 14F at the same instant. If we’re not careful, both succeed, and two people show up for one seat.
This is a race condition. The fix: changing a seat from available to held must be one safe, all-or-nothing action. Only one user can win that change; the other is told “sorry, just taken.”
- When a user reserves seat 14F, the system atomically checks “is it available?” and if so, flips it to held, in one step.
- The first request wins and gets the hold. The second sees it’s no longer available and is rejected.
So even with thousands clicking the same seat, exactly one hold succeeds. No double-booking.
⏰ The Hold Timeout
When a seat is held, a timer starts (say 5 minutes). Two things can happen:
- They pay in time: the seat moves from held to booked. Done.
- They don’t pay in time: the hold expires and the seat goes back to available, so someone else can grab it.
How do we expire holds? A common trick is to store the hold with an automatic expiry (a fast store like Redis can drop a key after a set time). When the timer ends, the seat is free again without anyone having to remember to release it.
Without a timeout, seats leak
If a held seat never auto-released, anyone who started checkout and walked away would lock that seat forever. The timeout is essential: it returns abandoned seats to the pool automatically.
🏗️ High-Level Design
Putting it together.
Reading the parts:
- The booking service handles reserving, holding, and confirming seats.
- A fast seat store (Redis) tracks holds with automatic expiry, perfect for timeouts.
- The database keeps the permanent record of events, seats, and confirmed bookings.
- The payment service processes payment; on success, the booking is confirmed.
📈 Handling the Rush
Popular events bring a spike, much like a flash sale:
- A load balancer spreads the flood across many booking servers.
- The fast seat store handles the hot reserve-and-hold actions in memory.
- A waiting room is common: extra users wait in a virtual line and are let in steadily, so the system isn’t hit by everyone at once.
🧰 Tech Choices
Part of system design is not just naming pieces, it’s saying why you picked each one. Here are the main technology decisions for this system and the reason behind each.
| Decision | Choice | Why |
|---|---|---|
| Hold seats during checkout | Redis with auto-expiry | Fast holds that release themselves when the timer runs out. |
| Stop double-booking | Atomic available→held change | Only one user can win a seat, even under a rush. |
| Permanent bookings | Relational database | Durable, consistent record of events, seats, and confirmed bookings. |
| Survive a hot sale | Load balancer + waiting room | Spreads the flood and admits users at a safe pace. |
⚠️ Common Mistakes and Misconceptions
A few things to keep straight:
- “Check if a seat is free, then mark it taken in a separate step.” That gap lets two people grab the same seat. The check-and-hold must be one safe action.
- “Held seats can stay held until the user comes back.” No. Holds need a timeout, or abandoned seats are locked forever and never sell.
- “Confirm the booking before payment succeeds.” The seat should only become booked after payment is confirmed; until then it’s just held.
🧩 What You’ve Learned
Nice work. Here’s the recap:
- ✅ A ticketing system reserves specific seats, holds them during checkout, then confirms or releases them.
- ✅ A seat has three states: available, held (with a timer), and booked.
- ✅ Changing a seat from available to held must be one safe action, so two people can’t book the same seat.
- ✅ A hold timeout automatically returns abandoned seats to the pool, often using a store with auto-expiry like Redis.
- ✅ A load balancer and a waiting room help the system survive the rush for popular events.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What makes ticketing harder than a plain limited sale?
Why: Ticketing must hold a specific seat for a buyer while they pay, with a timeout. That hold-and-release is the unique challenge.
- 2
What are the three states of a seat?
Why: A seat is available, then held while a user pays, then booked once payment succeeds (or back to available if the hold expires).
- 3
How do we stop two people from booking the same seat?
Why: If checking and holding a seat is one atomic step, only the first request wins. The second is told the seat is taken.
- 4
Why do held seats need a timeout?
Why: Without a timeout, anyone who starts checkout and leaves would lock a seat forever. The timer frees abandoned seats automatically.
🛠️ Design Challenge
Try extending the ticketing system yourself. Think each one through first, then open the answer to see a full breakdown.
Best-available seats. Many users don’t care which seats, they just want “3 seats together.” How would you handle that?
Limiting seats per user. Stop one person from holding 50 seats and blocking everyone. How do you cap it?
A waiting room for a hot sale. When a huge concert opens, millions arrive at once. How do you keep the booking system from being crushed?
🚀 What’s Next?
You’ve designed a ticketing system. Let’s connect it to related problems.
- Design a Coupon / Flash-Sale System shares the “limited stock, huge rush” challenge.
- Redis Introduction is the fast store behind holds and timeouts.
Get these down and you’ll handle any booking or limited-inventory design with confidence.