A railway reservation system is not a seat-booking system with more rows. Segment-wise inventory, waitlist and RAC, quota partitioning and the Tatkal thundering herd make it one of the hardest booking problems asked in Indian system design interviews.
Indian Railways runs roughly 13,000 passenger trains a day and carries on the order of 2.3 crore passengers. Reservation volume is a fraction of that, but it arrives in an extremely uneven shape: a large share of the day's booking attempts land in the two minutes after Tatkal opens. Designing for the daily average here is the classic mistake — the system is defined by its peak, not its mean.
~2-5 lakh users converge in the first 60 seconds
A few tens of thousands → contention ratio ~10:1 or worse
Booking writes settle to low hundreds/sec
Primary takeaway: peak-to-average is roughly three orders of magnitude, and autoscaling cannot react inside a 60-second spike. Capacity for Tatkal has to be provisioned before the window opens, and the excess demand has to be absorbed by a queue rather than rejected at the database.
This is the part that makes railway booking genuinely different from booking a cinema seat, and it is where most candidates go wrong. A berth is not simply free or taken. A train from Delhi to Chennai stops at a dozen stations, and berth B-32 can legitimately be sold three times over on the same journey — Delhi to Bhopal, Bhopal to Nagpur, Nagpur to Chennai — as long as those spans do not overlap.
Number the halts 0…N. The gap between consecutive halts is a segment. A booking from halt i to halt j consumes segments i through j-1. Availability for a requested span is then the minimum free count across the segments it covers.
berth_occupancy[B-32] = 0b00111000
available(i, j) = (occupancy & span_mask(i, j)) == 0
A bitmask per berth makes the check a single AND, and the allocation a single OR. With a few hundred berths per train and fewer than 64 halts on almost every route, the entire inventory for one train on one date fits comfortably in memory and can be held in a single Redis hash or an in-process cache on the coach's owning shard.
A candidate who models inventory as a flat seat count per train will produce a design that under-sells the train badly, because every short-hop booking blocks a berth for the entire route. Interviewers ask about intermediate stations precisely to see whether you reach for segments. It is the single highest-signal moment in this question.
Inventory is not one pool. Each coach's berths are carved into quotas before booking opens — General, Tatkal, Premium Tatkal, Ladies, Senior Citizen, Divyangjan, plus remote-location and defence quotas on many routes. A Tatkal berth is simply not visible to a general booking, even when it is physically empty.
Design note: quota partitioning is a natural sharding key. Treat (train, date, class, quota) as the unit of inventory ownership and a single node can own it outright — which removes distributed locking from the hot path entirely.
At 10:00:00 a few lakh clients submit within the same second for a few thousand berths. Letting that reach the database is how the system falls over. The shape of the answer is to admit the load, order it, and serve it at the rate the inventory can actually absorb.
Every request gets a token and a position. The user sees a queue position rather than an error, which is both better product and better engineering — retry storms from rejected users would otherwise double the peak.
Consumers pull from the queue at a rate the owning shard can commit. Once the pool for a train is exhausted, every remaining token for it can be resolved as waitlist immediately, without touching inventory at all.
A berth is held for the duration of payment — a short TTL, single-digit minutes — then released automatically if payment does not confirm. The hold must expire on its own, never on a cleanup job that might not run.
A spike that peaks in 60 seconds is over before new instances finish warming. Capacity is scheduled against the Tatkal clock, and caches for the day's popular trains are warmed before the window opens.
Tatkal has a long history of automated booking. Practical defences — per-account and per-IP limits, device attestation, a CAPTCHA inside the window, and ordering strictly by server-side admission time rather than by whose retry loop is tightest — are worth raising. Interviewers looking for product judgement notice when a candidate treats abuse as part of the design rather than an afterthought.
When a quota is exhausted the booking does not fail. It enters RAC — a confirmed seat shared between two passengers, no berth — or the waitlist, an ordered queue. Both are promoted as cancellations arrive, and settled in a batch when the chart is prepared a few hours before departure.
WL/n → RAC/m → CNF (berth)
any state → CAN (refund by slab at cancellation time)
A cancellation frees specific segments, not a whole berth. The promotion scan has to find the head-of-queue waitlist entry whose requested span actually fits the freed segments — strict FIFO can be unfillable, which is why the real system promotes by position within a compatible span.
At charting, unsold quota berths are released to general, RAC is promoted against them, waitlist is promoted against RAC, and whatever remains unconfirmed is cancelled and refunded. It is a bulk job over one train's inventory — which the per-(train, date, class) ownership model makes a single-node operation.
Interview angle: waitlist and RAC have no equivalent in cinema or airline booking, so they are where the question stops being generic. Being able to say what happens to a WL/14 passenger at charting, and why the refund is automatic, separates someone who has thought about the domain from someone reciting a booking-system template.
Allocation is the one place that needs serialisability. Because inventory is owned per (train, date, class, quota), that serialisation is local: a single-shard transaction or an in-memory single-writer, not a distributed lock. Availability reads can be served from a replica or cache with seconds of staleness — a slightly stale count is acceptable, a double allocation never is.
A PNR carries up to six passengers, each with an independent status — some confirmed, some RAC, some waitlisted. The PNR is the transactional aggregate for payment and refund; the passenger is the unit of allocation. Conflating the two breaks partial cancellation.
The payment gateway is external and slow; the berth hold is internal and fast. Holding a database transaction open across a gateway call is how the whole pool stalls behind one slow bank.
1. reserve segments, status = HELD, TTL ~10 min
2. redirect to payment, carry an idempotency key
3a. success → commit CNF, issue PNR
3b. failure or timeout → hold expires, segments return to the pool
Yes. This question is asked as design IRCTC, design a railway reservation system, design a train booking system, or simply Tatkal booking system design. Interviewers sometimes name the product and sometimes describe it, but the problem underneath is identical — segment-wise berth inventory, quota pools, waitlist and RAC, and a demand spike the database cannot absorb directly.
It is a different question from designing BookMyShow, even though both are “booking systems”. Cinema seats are sold for one show and one span; railway berths are sold repeatedly along a route. If you answer one with the other's design, the intermediate station follow-up will expose it.