← All posts
Problem WalkthroughsJuly 25, 202612 min read

Design Uber (Ride-Matching) — System Design Interview Walkthrough

"Design Uber" (or Lyft, or a food-delivery dispatch) is the canonical geospatial system design problem. Its heart is a question most other problems never ask: how do you efficiently find "the nearest available drivers" among millions of constantly-moving points, thousands of times per second? Get the location indexing and the matching flow right and the rest follows. Here's the walkthrough.

Step 1 — Clarify requirements

Functional

  • Drivers come online and continuously report their location.
  • A rider requests a ride from A to B.
  • The system matches the rider with a nearby available driver and coordinates the trip.
  • (Optional) ETAs, pricing/surge, trip tracking.

Non-functional

  • Low-latency matching — a rider shouldn't wait long for a match.
  • Very high write throughput — millions of drivers pushing location updates every few seconds.
  • High availability and geographic scale (works per city/region).
  • Reasonable consistency — a driver shouldn't be matched to two riders at once.

The two hard parts, stated up front: absorbing the flood of location updates, and querying "who's nearby" fast.

Step 2 — Back-of-the-envelope

Say 1 million active drivers, each sending a location update every ~4 seconds → ~250,000 location writes per second, continuously. That number alone tells you locations can't live in a normal transactional database updated per write — you need an in-memory, geo-optimized store. Ride requests are far fewer (thousands/second), but each triggers a spatial query.

Step 3 — The core problem: geospatial indexing

You need to answer "which available drivers are within X of this point?" quickly. A naive scan over all drivers is hopeless. The standard tools:

  • Geohash — encode a lat/long into a short string where a shared prefix means spatial proximity. "Nearby" becomes a prefix match, which is easy to bucket and query. Simple and widely used.
  • Quadtree — recursively subdivide space into quadrants; dense areas subdivide further. Good for uneven density (a busy downtown vs. empty suburbs).
  • S2 / H3 — Google's and Uber's hierarchical cell systems that tile the globe into cells at multiple resolutions; a location maps to a cell, and neighbors are cheap to enumerate. (Uber famously uses H3.)

The idea in all three: bucket the map into cells, keep the set of drivers per cell, and answer a proximity query by looking at the rider's cell and its neighbors — turning a global search into a handful of small lookups.

Step 4 — Handling location updates

Driver locations are high-write and ephemeral, so keep them in a fast in-memory store (e.g., Redis, which has geospatial commands), keyed by geo-cell. Each update just moves a driver into the right cell. You don't need durable history of every ping on the hot path — persist a sampled trail asynchronously if you need it later.

A common design: a location service ingests updates (often through a queue to smooth spikes) and maintains the current driver-per-cell index in memory. This absorbs the 250k writes/second without touching the primary database.

Step 5 — The matching flow

When a rider requests a ride:

  1. Compute the rider's geo-cell.
  2. Query that cell and its neighbors for available drivers, expanding the radius if none are found nearby.
  3. Rank candidates (by distance/ETA), then dispatch the request to the best one.
  4. Reserve that driver so they can't be double-matched — mark them unavailable atomically while the offer is outstanding; if they decline or time out, release and try the next candidate.

That reservation step is where consistency matters: use an atomic operation/lock so two riders can't both grab the same driver. Matching itself can be greedy (nearest first) or batched (optimize assignments over a short window for better global efficiency) — mention the trade-off.

Step 6 — Trip lifecycle and related concerns

  • During the trip, the driver keeps sending location updates, now streamed to the rider for live tracking (a real-time channel, like the chat problem).
  • ETA/routing is typically a separate service (map + traffic data) — treat it as a dependency, not something you build inline.
  • Pricing / surge is a separate concern from matching: it's computed from supply/demand per area, not baked into the dispatch loop. Keeping it separate is a clean-design signal.

Step 7 — Follow-ups interviewers love

  • "How do you find nearby drivers efficiently?" Geo-cell index (geohash/S2/H3) + neighbor lookup — the crux.
  • "How do you handle 250k location writes/second?" In-memory geo store, updates via a queue, no per-write DB hit.
  • "How do you prevent a driver being matched to two riders?" Atomic reserve/lock while an offer is pending; release on decline/timeout.
  • "What about a surge of requests in one area (a concert letting out)?" Hot cell / thundering herd — the neighbor-expansion and batched matching help; scale the region's shards.
  • "Greedy vs. batched matching?" Greedy is simple and fast; batching over a short window yields better overall assignments at the cost of a little latency.

Common mistakes

  • Scanning all drivers for each request instead of using a spatial index — the whole problem is avoiding that.
  • Writing every location ping to a relational database — it won't survive the write volume; use an in-memory geo store.
  • No reservation/locking — leads to double-matching a driver.
  • Bolting pricing into matching — surge is a separate service driven by supply/demand.

Practice this out loud

The geospatial angle makes this problem distinctive, and interviewers dig into "how exactly do you query nearby drivers?" and "how do you not double-book?". On Whitepad, a ride-matching design is a preset problem: a senior AI interviewer runs it by voice, watches your whiteboard, and probes your geo-indexing, write-throughput, and reservation choices in real time — then scores you like a real interviewer. Talk through the matching loop until it's automatic.

Practice this out loud

Reading is the easy part. Sit across from a senior AI interviewer that talks, watches your whiteboard, and scores you like the real thing — your first mock is free.

Start a free mock →