Table of Contents

“Design Uber.”

This is a classic system design interview question — and one that often causes a complete mental blank because it’s so large and so vague. Where do you even start?

This post summarizes a live system design session, sharing the thinking framework that works for these kinds of open-ended problems.

TL;DR

Designing Uber isn’t about memorizing which technologies to use. It’s about building a reusable thought process: clarify scope → identify core challenges → propose solutions → analyze trade-offs.

Step 1: Narrow the Scope

Uber is a full product ecosystem — passenger app, driver app, admin backend, payments, mapping. If you try to design everything at once, you design nothing well.

In an interview, the first move is to define boundaries:

  • Focus only on the core flow: passenger requests a ride → driver accepts
  • Exclude payments, ride history, and ratings (these can be addressed if time permits)
  • Assume third-party mapping (Google Maps API), not self-built

This looks simple, but the interviewer is watching whether you proactively define the problem boundary rather than waiting to be told.

Step 2: Identify the Core Challenges

Uber’s technical challenge is fundamentally a location matching problem:

  1. Where is the passenger?
  2. Where are nearby drivers?
  3. How do you match the best driver to the nearest passenger?

Three key sub-problems worth exploring:

Real-time location updates: Drivers update their location every few seconds — a write-heavy workload at scale.

Nearby driver queries: When a passenger requests a ride, the system needs to quickly find available drivers within X km — a geospatial query. Standard SQL performs poorly for this; you need a geospatial index or a dedicated geo database.

Matching logic: Once you have candidates, how do you pick? Closest? Highest-rated? Shortest ETA? This decision shapes the system architecture.

Step 3: Data Model and Core APIs

Driver Location table:

driver_id    | VARCHAR
latitude     | FLOAT
longitude    | FLOAT
status       | ENUM (available, busy, offline)
updated_at   | TIMESTAMP

Ride Request table:

request_id   | UUID
passenger_id | VARCHAR
pickup_lat   | FLOAT
pickup_lng   | FLOAT
status       | ENUM (pending, matched, completed, cancelled)
driver_id    | VARCHAR (nullable, set after match)
created_at   | TIMESTAMP

Core APIs:

  • POST /ride/request — passenger initiates ride
  • PATCH /driver/location — driver updates position (high-frequency)
  • GET /ride/{id}/status — polling or WebSocket for match result

Step 4: Scalability Trade-offs

Write pressure from location updates: 1 million active drivers updating every 4 seconds = ~250,000 writes/second. A relational database (e.g. PostgreSQL) would bottleneck here. Common approach: write to Redis (in-memory, ultra-low latency) and asynchronously sync to persistent storage.

Geospatial queries: Redis GEO commands (built on sorted sets + geohash) let you query “all keys within N km of a given point” — far faster than range queries in a relational DB.

Service separation: Location update service, matching service, and ride status service should be deployed independently so that a traffic spike in one doesn’t cascade to the others.

The Bigger Picture

What the “Design Uber” question is really testing is whether you can use engineering language to break a complex real-world problem into bounded, progressively deeper sub-problems — not whether you can recite “use Kafka + Redis + Kubernetes.”

In interviews, demonstrating a clear thought process and proactively surfacing trade-offs matters more than arriving at the “correct” answer — because there is no single correct answer in system design, only answers that are reasonable given the current constraints.

References

Tags

Related Articles

Engineering Lessons from Building Cursor: From VSCode Fork to $500M ARR

Cursor is an AI-powered code editor by Anysphere, built by four MIT graduates, that hit $500M ARR within two years of launch. This article distills the real engineering lessons they've shared publicly: why they forked VSCode instead of building an extension, how Tab prediction's latency engineering works, and the hard production lessons from shipping Agent Mode.