Think Beyond the Happy Path
Real production systems aren't just about matching riders and drivers — they're about real-time coordination, geo-spatial efficiency, and consistency under pressure.
Before diving into the material, take a moment to ask yourself:
- Do you know how to process millions of location updates per second while keeping the data fresh for matching?
- Do you know the trade-offs between QuadTree and GeoHash for spatial indexing, and when to use each?
- Do you know how to ensure strong consistency so that one driver never gets assigned to multiple riders simultaneously?
- Do you know how to handle peak hours when ride requests spike 5-10x normal traffic?
You don't need to answer all of these right away. A Senior/Staff+ Engineer doesn't stop at basic functionality — they anticipate edge cases, design for resilience, and push for production-grade reliability.
But great systems start with great questions. What would you ask next?
Problem Statement
Design a ride-sharing platform like Uber that allows riders to request rides, matches them with nearby drivers in real-time, and provides navigation for drivers. The system should:
- Allow riders to request rides and receive fare estimates.
- Match riders with nearby available drivers within minimal wait time.
- Enable drivers to accept rides and navigate to pickup locations. And the scale is millions of active drivers with location updates every 5 seconds.
What makes Uber different from Yelp?
What are interesting talk points or challenges in designing Uber compared to Design Yelp?
- Similarity
- Both require you to have some base domain knowledge on "how to process (store/query) location data". I.e., find nearby (restaurants vs drivers in this case).
- Difference
- A unique challenge with designing Uber is "how to manage and process real-time location updates at scale". Drivers will need to frequently report their location in order for the system to do efficient rider-driver matching. So how the system handles heavy writes (location update) and then does efficient matching, is an interesting topic (deep-dive point) for this particular question (and it cannot be missed!)
Functional Requirements
FR1 – Request Ride and Get Estimates
Rider should be able to request a ride with source/destination and get fare estimates.
FR2 – Match Nearby Driver
Rider should be able to match a nearby driver within a minimal wait time (< 30 seconds).
FR3 – Accept Ride and Navigate
Driver should be able to accept ride requests and navigate to the rider's location.
Non-Functional Requirements
NFR1 – Low Latency Matching
The system should prioritize low-latency for ride matching to ensure quick response times for both driver and rider.
NFR2 – Strong Consistency
The system should ensure strong consistency on rider-driver matching. Specifically:
- One ride is not matched to more than one driver at a time;
- One driver does not get assigned with multiple riders at the same time;
NFR3 – High Availability
The system should be highly available and minimize downtime, ensuring requests can be processed 24/7.
NFR4 – High Throughput
The system should be able to handle high throughput during peak hours or events.
Requirement Summary
| Functional Requirements (FRs) | |
|---|---|
| Name | Description |
1. Request Ride and Get Estimates | Rider requests a ride with source/destination and receives fare estimates. |
2. Match Nearby Driver | Match rider with nearby available driver within < 30 seconds. |
3. Accept Ride and Navigate | Driver accepts ride requests and gets navigation to rider location. |
| Non-Functional Requirements (NFRs) | |
|---|---|
| Name | Description |
1. Low Latency Matching | Quick response times for driver-rider matching. |
2. Strong Consistency | No double-booking: one driver per ride, one ride per driver. |
3. High Availability | System operational 24/7 with minimal downtime. |
4. High Throughput | Handle traffic spikes during peak hours and events. |
Below the Line (Out of Scope)
Additional Features to Consider
- Rider & driver rating (review each other)
- Schedule in advance (schedule a pickup with future time)
- Request different type of cars (UberX, UberX Priority, UberShare)
- Change rides (i.e., update drop-off location)
Core Entities
To tie these requirements together into a coherent architecture, we begin with the foundational building blocks of the system.
Ride — The Trip Request
A Ride represents a trip request from a rider. It tracks:
- Source and destination locations
- Fare estimate and actual fare
- Current status (requested, matched, in_progress, completed)
- Assigned driver (once matched)
| Rides Table | |||
|---|---|---|---|
| Field | Type | Key | Description |
ride_id | UUID | PK | Unique ride identifier. |
rider_id | UUID | FK → users(user_id) | Who requested the ride. |
driver_id | UUID | FK → drivers(driver_id), NULLABLE | Assigned driver. |
source_lat | FLOAT | NOT NULL | Pickup latitude. |
source_lng | FLOAT | NOT NULL | Pickup longitude. |
dest_lat | FLOAT | NOT NULL | Destination latitude. |
dest_lng | FLOAT | NOT NULL | Destination longitude. |
estimated_fare | DECIMAL | NOT NULL | Calculated fare estimate. |
actual_fare | DECIMAL | NULLABLE | Final fare after completion. |
status | ENUM | NOT NULL | requested/matched/in_progress/completed/cancelled. |
created_at | TIMESTAMPTZ | NOT NULL DEFAULT now() | Request timestamp. |
Driver — The Service Provider
A Driver represents a driver in the system. It tracks:
- Current status (online, offline, on_ride)
- Current location (updated frequently)
- Lock status for matching coordination
| Drivers Table | |||
|---|---|---|---|
| Field | Type | Key | Description |
driver_id | UUID | PK | Unique driver identifier. |
name | TEXT | NOT NULL | Driver name. |
status | ENUM | NOT NULL | online/offline/on_ride. |
vehicle_info | JSONB | NOT NULL | Vehicle details (model, plate, color). |
rating | DECIMAL | NOT NULL DEFAULT 5.0 | Driver rating. |
created_at | TIMESTAMPTZ | NOT NULL DEFAULT now() | Registration timestamp. |
API Design
For designing Uber, some additional APIs are required. For example, APIs for drivers to report their real-time locations and status changes (picked up, dropped off etc).
Keep in mind that system design interview time is limited. It's recommended spending no more than 5-6 minutes on API design. Instead, focus on two key areas that will help you stand out:
- Your high-level design: How your system addresses the core functional requirements
- A strategic deep-dive(s): How your design satisfies all non-functional requirements
So the suggested approaches are:
- Start with just the core APIs - the ones directly tied to your main requirements. (3 functional requirements → 3 APIs) That's sufficient for now.
- Be proactive and mention that you'll introduce additional APIs during the high-level design discussion. For instance: "I'll detail the driver location reporting API when we discuss the rider-driver matching component."
1. Rider requests a ride
POST /ride/cost --> <Ride_Information> (rideId, cost...)
{
riderId (or JWT token),
source, (raw address)
destination,
}
2. Rider accepts a ride
PATCH /ride/rider/accept --> 200 or <estimated waiting time to get a driver>
{
rideId
true (accept) / false (deny)
}
3. Driver accepts a ride request
PATCH /ride/driver/accept --> 200 or <navigation info to rider location>
{
rideId
true (accept) / false (deny)
}