Ride matching
Design the matching part of a ride-hailing service. A rider requests a ride from where they are standing; the system finds a nearby driver, offers them the trip, and confirms the match. Drivers move continuously and can decline.
Where’s the slack?
Match: ~10 seconds, and every second is visible.A person is standing on a street with a phone in their hand. There is no cooking time and no processing window to hide latency inside. Few problems in this app have less slack.
Compare this to food delivery, which looks like the same problem. There, a courier does not need to be assigned the moment the order is placed. The restaurant needs 15 minutes to cook, and the system can spend several of those minutes finding the best courier, batching orders together, and waiting for a better option to come free. Those 15 minutes are slack, and they make a different design possible: batched optimisation rather than immediate assignment.
Ride hailing has none of it. The rider is outside, possibly in the rain, watching a spinner. Ten seconds without a driver feels broken; after thirty they may open a competing app. So matching must be greedy and immediate: take a good driver now, not the best driver in forty seconds. That rules out global optimisation, which is the elegant answer and the wrong one here.
There is one small pocket of slack: the few seconds between offering a trip to a driver and their tap. That window lets you sequence offers rather than blasting all candidates at once. But the rider is waiting through it and other drivers are moving away, so it is measured in seconds and cannot be spent freely.
Everything not on the matching path (receipts, ratings, driver earnings, analytics) has hours of slack and should be nowhere near this design.
So: Zero slack means greedy immediate matching, not batch optimisation. It also means the failure branches (nobody accepts, everybody declines) are the design, because they happen while a human is watching.
Work it through
Five stages, gated. You write your answer for each stage before its model answer unlocks. That is the core of the method.
Reference material for this problem. The diagrams below are here to check your own against once you have drawn it, not to read first.
The lifecycle
The numbers
All live positions fit in 10 MB. That number says the live index belongs in memory, not in a database, and that durability for a position that expires in 4 seconds is money spent protecting nothing.
The architecture
The mechanism
The decision this turns on
- —Offer to the best available driver right now and commit.
- —Match in seconds, which is the only budget that exists here.
- —Globally worse assignments, with longer average pickups.
- —Simple to reason about and to debug during an incident.
- —Collect requests for 30–60 seconds, then assign the whole set optimally.
- —Noticeably better assignments overall, and it can pair trips going the same way.
- —Requires slack that ride hailing does not have: the rider is outside, waiting.
- —Right for food delivery, where 15 minutes of cooking hides the delay completely.
Follow-ups you should expect
Many interviews are decided in the follow-ups, not the first diagram.
Same shape, other products
Two sides need to find each other, and one of them is a human who is waiting.
Supply moves, demand is impatient, and the interesting design is what happens when nobody accepts, rather than the happy path.
Others with this shape: Ride hailing · Food delivery dispatch · Any two-sided marketplace
How it is really built
Write your own answer first. Then read how teams who run this at scale describe it. Their constraints were real, and the write-ups often say what their choices cost.
- H3 — indexing the globe ↗Uber's open-source hexagonal grid, an alternative to geohash cells for this kind of lookup.