Movie ticket booking
Seats, shows and temporary holds: how to let many people pick seats at once without selling the same seat twice.
On the roadmap:Software Design · step 5: Low-level design: bookings and payments
Lesson 5 of 16 · 11 min read · quiz · exercise
The problem
A theatre chain runs screens that show movies at set times. Customers browse shows, pick seats, pay and receive a ticket. Many customers pick seats for the same popular show at once. A seat must never be sold twice.
Entities
Figure SDA-LLD-05-1 · Movie booking classes · © forcsguy.com
The key idea: ShowSeat is a seat in one show. A physical seat exists for all shows; it is available or taken per show. Status values: AVAILABLE, HELD, BOOKED.
The seat lifecycle
Figure SDA-LLD-05-2 · Show seat status · © forcsguy.com
class ShowSeat {
status: "AVAILABLE" | "HELD" | "BOOKED" = "AVAILABLE";
heldBy?: string; heldUntil = 0;
// must be atomic: a lock per seat in memory, a conditional UPDATE in a database
tryHold(user: string, ms = 10 * 60_000): boolean {
if (this.status === "HELD" && Date.now() > this.heldUntil) this.status = "AVAILABLE";
if (this.status !== "AVAILABLE") return false;
this.status = "HELD"; this.heldBy = user; this.heldUntil = Date.now() + ms;
return true;
}
confirm(user: string): boolean {
if (this.status !== "HELD" || this.heldBy !== user) return false;
this.status = "BOOKED"; return true;
}
}
In a database this is one statement: UPDATE show_seat SET status='HELD', held_by=?, held_until=? WHERE id=? AND (status='AVAILABLE' OR held_until < now()) and the affected-row count tells you whether you won.
Booking several seats
Figure SDA-LLD-05-3 · Booking flow · © forcsguy.com
If any seat in the group cannot be held, release the ones you did hold and tell the customer. This avoids a half-booked group.
Design notes
- Pricing by seat category, time and day is a strategy or a price table on
ShowSeat. - Expiry can be a background job or a check at read time (as above). A job keeps the displayed seat map accurate.
- Hot shows: at huge scale put the seat state in a fast store with atomic operations, and queue requests; this overlaps with the flash-sale design in the real-world systems course.
- Idempotent payment: a retried payment callback must not issue a second ticket.
- Extensions: seat recommendations, food add-ons, cancellations with refund policy, and notifications on confirm.
Real-world reading
Related reading
- Rewriting the heart of our sync engineDropboxCase Studies
- Megastore: Providing Scalable, Highly Available Storage (paper)Baker et al. · GooglePapers
- Scaling Dropbox - Kevin Modzelewski, Back-end Engineer at DropboxDropboxYouTube
- Hussein Nasser: Backend Engineering ShowHussein Nasser · Hussein Nasser (YouTube)YouTube
Show 6 moreShow fewer
- Uber Engineering — Where the Digital World Meets the Physical OneUber engineers · UberBlogs
- Handles Millions of Digital Transactions Safely Everyday at PaytmPaytm engineers · PaytmCase Studies
- Distributed systems theory for the distributed systems engineerHenry Robinson · The Paper TrailBlogs
- The Pragmatic EngineerGergely Orosz · SubstackPodcasts & Newsletters
- Soundcloud Engineering BlogSoundcloud engineers · SoundcloudBlogs
- Pluralsight Engineering BlogPluralsight engineers · PluralsightBlogs
Check your understanding
Question 1 of 3
0 correct so far
Why use a temporary seat hold with an expiry?
Practise it: URL shortener
Everything below is already set up for this lesson: change the design, run the traffic, and see whether you meet the goal.
- 1The task
- 2Build and test
Read-heavy, a few links are very popular.
Add or remove parts, move traffic up and down, and break something to see what gives way first.
Try it yourself
Add a group booking for 4 adjacent seats, and a 10-minute hold. How do you keep it correct?
Click what a strong design here would need:
More in Design practice
© 2026 forcsguy.com. Original lesson text and diagrams. Books and sites linked above belong to their authors.