Free full guide

Uber (Ride Hailing)

Design Uber — a ride-hailing platform matching riders to nearby drivers in real time, with live location tracking, pricing, and trip lifecycle management.

00

Practice checkpoints

The interview rhythm stays compact, so the page can spend attention on the actual design decisions.

  1. 01
    Clarify scope
  2. 02
    Requirements + scale
  3. 03
    API + data model
  4. 04
    Draw architecture
  5. 05
    Deep dive
  6. 06
    Trade-off decision
01

Requirements that shape the design

Do not only state requirements. Ask for them. Each card pairs the design constraint with a clarification question you can say out loud before drawing the architecture.

Functional requirements

01What does the rider see first — a price before they commit?

Riders enter pickup and destination and get a fare estimate (price + ETA) before requesting the ride.

02What happens after they tap request — how fast must a match come back?

Riders request a ride at the estimated fare and get matched to a nearby available driver — or a clear failure — within about a minute.

03What does the driver side do?

Drivers go online, send location pings, receive one ride offer at a time, and accept or decline; on accept they navigate to pickup and drop-off.

04Can a rider cancel after matching, and what does the driver experience?

Yes, with grace rules: cancellation atomically releases the driver back to available, and the ride state machine records who cancelled and when.

05Does the rider watch the driver approach live?

Yes: driver location streams to the matched rider only while the ride is active - everyone else sees coarse availability, never a trackable trail.

06No driver accepts inside the matching window - then what?

The request fails clearly with retry guidance - a definite no within the minute beats a spinner that never resolves.

Out of scopeRatings (rider and driver) · Scheduled rides and ride tiers (X/XL/Comfort) · Surge pricing mechanics and payment settlement

Non-functional requirements

01Can one driver ever get two rides at once?

Matching is strongly consistent: a driver holds at most one active offer or ride at a time — no double-dispatch, ever.

02How fresh do driver locations need to be?

Drivers ping every few seconds while online; proximity search may see data a few seconds old, never minutes.

03What write load should the location store plan for?

At a deliberate stress ceiling of 10M drivers online worldwide, pinging every ~5 seconds, the location store absorbs ~2M writes per second — that lives in memory, not in the relational database.

04What happens when a stadium lets out?

A burst of ~100K ride requests from one area queues and drains gracefully — nearby zones and other cities stay unaffected.

05How fast should each step feel?

Fare estimate in a couple of seconds; match (or a clear failure) within about a minute end to end.

Keep asking — the interview is a conversation

Real interviews probe far more than a tidy list. These are the scope questions that separate candidates who interrogate the problem from those who recite it.

  • Is fare estimation in scope, or do we start from the ride request?
  • How fresh do driver locations need to be — a few seconds stale acceptable?
  • One offer to one driver at a time, or broadcast to several and first-accept-wins?
  • What peak should matching plan for — steady city load or event bursts?
  • Are surge pricing and ratings out of scope?
02

Numbers that force architecture decisions

Treat every estimate as a pressure that justifies a component: cache, queue, partition, replica, worker pool, or fallback path.

01

Location write firehose

a stress ceiling of 10M drivers online worldwide × 1 ping every 5 s10,000,000 ÷ 5 ≈ 2M writes/s

No relational database absorbs this — locations go into an in-memory geo index (geohash/H3 buckets) with TTL eviction.

02

Proximity lookup cost

Pickup point → the geohash cell it falls in + 8 neighbor cells9 cell reads ≈ a few ms in memory

Geohashing turns "who is near me" into a handful of key lookups instead of a table scan.

03

Concert burst

~100K requests from one neighborhood over ~10 minutes100,000 ÷ 600 s ≈ 170 matches/s in one zone

Partition the matching queue by geo zone — the spike saturates one zone’s consumers, not the whole city.

04

Offer budget

Match within 60 s; each offered driver gets ~10 s to respond60 s ÷ 10 s ≈ 5-6 drivers tried before the deadline

The 10-second offer lock bounds how many candidates fit in the budget — rank candidates well, don’t spray offers.

05

Phantom-driver cleanup

Location entries carry a 15-30 s TTLno ping within TTL → entry expires

Drivers who crash or go offline vanish from the index on their own — no cleanup job, no offers to ghosts.

Decision example

The numbers

Two very different loads share this system: about 2M location writes per second stream in from drivers, while each ride match only needs a handful of nearby candidates within a minute.

My choice

I would keep driver locations in an in-memory geo index (geohash/H3 buckets) with a short TTL, so drivers who stop pinging simply disappear. Matching pulls nearby candidates and offers the ride to one driver at a time, locking that driver for about 10 seconds — accept wins the ride, timeout or decline releases the lock and the next candidate gets the offer. Ride requests during a spike wait in a queue partitioned by area, so a stadium letting out slows that neighborhood, not the whole city.

Avoid

What I would NOT do: write every location ping into the main database and scan it to find nearby drivers — 2M writes per second plus scans kills it. I also would not offer one ride to several drivers at once without a lock: two accepts arrive together and both drivers think they got the job. And I would not shard the matching system on day one — measure the per-zone rate first; premature sharding adds failure modes without adding capacity you need.

Change if

If match quality matters more than speed — pooled rides, batching — I would collect requests for a few seconds and match them in small batches instead of one at a time.

03

Architecture path

Draw the write path and the read path as separate lanes — they carry different traffic and justify different components.

Uber (Ride Hailing) serviceRequest path — estimate, request, matchRider AppRide ServiceMatching ServiceGeo Index (nearbydrivers)Driver Offer (10s)Location path — the write firehoseDriver AppAPI GatewayLocation ServiceGeo Index(geohash/H3)TTL EvictionRide DB (state)ride lifecycleNotificationServiceoffer → driverMapping Providerfare + ETAservicestorequeue / logexternalasync

Driver pings flow straight into the in-memory geo index; matching reads nearby candidates from it and offers rides one driver at a time. Ride truth lives in the database — the index is disposable.

Fare first, then request. Matching pulls a handful of nearby candidates and offers one driver at a time; the 10-second lock prevents double-dispatch and moves on automatically when a driver ignores the offer.

About 2M pings per second land in memory, bucketed into geohash/H3 cells; entries expire after 15-30 seconds so drivers who stop pinging vanish on their own.

04

API and data model

Before optimizing, make the contract inspectable: endpoints, entities, ownership, retries, and state.

POST/fare

req{ pickup, destination }

res200 { fare_id, estimated_fare, eta }

Calls the mapping provider for route + ETA; the estimate is saved so the ride request can reference it.

POST/rides

req{ fare_id }

res201 { ride_id, state: requested } · 404 fare expired

Kicks off matching; the rider gets the match result pushed (or polls).

POST/drivers/location

req{ lat, lng }

res200

Driver identity comes from the session token, never the request body. High-frequency write straight into the geo index.

PATCH/rides/{ride_id}

req{ accept | decline }

res200 ride · 409 offer expired

Accept flips the offer atomically; decline or a 10-second timeout releases the driver and the next candidate gets the offer.

Core entities

Rider

rider_id (PK) · payment_profile

Driver

driver_id (PK) · vehicle · status: offline/available/offered/on_trip

The status field is the double-dispatch guard: only an available driver can receive an offer, and the flip is atomic.

Fare

fare_id (PK) · pickup · destination · estimated_fare · eta

Created at estimate time; the ride request references fare_id so the quoted price cannot silently change.

Ride

ride_id (PK) · rider_id · driver_id · fare_id · state: requested/matched/in_progress/completed

DriverLocation

driver_id · lat/lng · updated_at

Lives in the in-memory geo index (geohash/H3 cells with a TTL), not the relational store — it is disposable data.

05

Deep dive directions

Pick one lane for the final third of the interview. Each lane gives you the topic, the interviewer question it should answer, and the failure mode to avoid.

01

FocusThe location firehose

Ask10M drivers ping every 5 seconds. Where do 2M writes per second go, and how do you answer "who is near this pickup"?

AvoidWriting pings to the main database and scanning for proximity — it dies at this rate.

02

FocusNever dispatch one driver twice

AskTwo ride requests want the same nearby driver at the same moment. How does exactly one win?

AvoidOffering to many drivers at once with no lock — two accepts both think they won.

03

FocusDriver does not answer

AskThe offered driver ignores the request. What happens at second 10, and how does the ride still match inside a minute?

AvoidBlocking the ride on one unresponsive driver instead of a lock TTL that moves on.

04

FocusA stadium lets out

Ask100K people request rides from one neighborhood in minutes. How do you keep the rest of the city unaffected?

AvoidOne global matching queue — a local spike becomes a citywide outage.

05

FocusPhantom drivers

AskA driver app crashes while marked available. How long can they still receive offers, and what cleans them up?

AvoidNo TTL on location entries — offers keep going to drivers who left an hour ago.

Ready to practice?

Talk through Uber (Ride Hailing) out loud and get AI scoring on the explanation.

Practice this with AI →