How to Design Uber — System Design Interview Question & Answer
Designing Uber is a classic senior/staff-level system design interview question because it combines real-time location tracking, geospatial search, matching, distributed systems, payments, event streaming, and high availability.
A strong interview answer should not start with databases or microservices. Start with requirements, scale, core workflows, and the hardest distributed-system problems.
1. Clarify the Requirements
Functional Requirements
We need to support:
-
Rider
- Sign up / log in
- Set pickup and destination
- Request a ride
- See nearby available drivers
- Track driver in real time
- Cancel a ride
- Pay for the ride
- Rate the driver
-
Driver
- Go online/offline
- Continuously send GPS location
- Receive ride requests
- Accept/reject requests
- Navigate to pickup
- Start/end trip
- Receive earnings
-
Platform
- Match riders with nearby drivers
- Calculate ETA
- Calculate fares
- Process payments
- Send notifications
- Maintain trip history
Non-Functional Requirements
The system should provide:
- Low-latency driver matching
- Real-time location updates
- High availability
- Horizontal scalability
- Fault tolerance
- Strong consistency for critical trip/payment state
- Eventual consistency where appropriate
- Idempotent APIs
- Secure payment processing
2. Back-of-the-Envelope Estimation
Assume:
- 100M registered users
- 20M daily active riders
- 5M active drivers
- 10M rides/day
- Peak: 10,000 ride requests/sec
- 5M drivers sending location updates
- Location update every 3 seconds
Driver location traffic:
5M drivers / 3 seconds
≈ 1.67M location updates/sec
This is already one of the most important architectural observations:
Location updates are much higher volume than ride requests.
Therefore, we should not store every GPS update directly in a traditional relational database.
3. High-Level Architecture



A simplified architecture:
┌─────────────────┐
│ Rider App │
└────────┬────────┘
│
┌────────▼────────┐
│ API Gateway / │
│ Load Balancer │
└────────┬────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Trip Service│ │ User Service│ │ Payment Svc │
└──────┬──────┘ └─────────────┘ └─────────────┘
│
▼
┌────────────────┐
│ Matching │
│ Service │
└───────┬────────┘
│
▼
┌────────────────┐
│ Geo/Location │
│ Service │
└───────┬────────┘
│
┌────┴─────┐
▼ ▼
Redis Kafka
Geo Index Event Bus
│ │
▼ ▼
Drivers Analytics
Location Notifications
The key architectural idea is:
Separate the real-time path from the durable data path.
4. Core Services
A reasonable service decomposition is:
| Service | Responsibility |
|---|---|
| API Gateway | Authentication, routing, rate limiting |
| User Service | Rider/driver profiles |
| Driver Service | Driver status and availability |
| Location Service | Real-time GPS updates |
| Geo Service | Nearby-driver queries |
| Matching Service | Rider ↔ driver matching |
| Trip Service | Trip lifecycle |
| Pricing Service | Fare calculation |
| Payment Service | Payment processing |
| Notification Service | Push/SMS notifications |
| Rating Service | Driver/rider ratings |
| ETA Service | Route and ETA calculation |
| Fraud Service | Fraud detection |
| Event Service | Async event processing |
Don’t create 30 microservices immediately in an interview.
A better statement is:
“These are logical boundaries. In a real system I’d initially group some of them into fewer deployable services and split them as scale and team ownership require.”
5. Driver Location Tracking
This is one of the hardest parts.
The driver app periodically sends:
POST /drivers/{driverId}/location
{
"lat": 51.5074,
"lng": -0.1278,
"timestamp": 1723200000
}
The Location Service:
Driver App
│
▼
Location API
│
├──► Redis / In-Memory Geo Index
│
└──► Kafka
│
├── Analytics
├── Historical storage
└── Fraud detection
Why Redis?
Because matching needs:
“Find available drivers within 2 km.”
That’s a geospatial query, not a traditional relational query.
Redis supports geospatial operations such as:
GEOADD drivers longitude latitude driverId
GEOSEARCH drivers ...
But at very large scale, we may use a dedicated distributed geospatial system.
6. Geospatial Indexing
Suppose a rider is here:
Latitude: 51.5074
Longitude: -0.1278
We need:
Find available drivers
within 2 km
There are several approaches.
Option 1 — Geohash
Convert coordinates into a geohash:
51.5074, -0.1278
↓
gcpvj0du
Nearby locations share prefixes.
For example:
gcpvj
├── gcpvj0
├── gcpvj1
├── gcpvj2
└── gcpvje
We can search the rider’s cell plus neighboring cells.
Option 2 — S2 Cells
Use hierarchical geographic cells:
World
└── Region
└── City
└── Cell
└── Sub-cell
This works particularly well for distributed geospatial systems.
7. The Matching Algorithm
Suppose a rider requests:
Pickup:
51.5074, -0.1278
Destination:
51.5150, -0.1410
Matching Service:
Rider
│
▼
Matching Service
│
▼
Nearby Driver Search
│
┌────────┼────────┐
▼ ▼ ▼
D1 D2 D3
0.5km 0.8km 1.2km
│ │ │
└────────┼────────┘
▼
ETA Service
│
▼
Rank Drivers
│
▼
Select Driver
We shouldn’t simply choose the physically closest driver.
A better scoring function might be:
score =
w1 * ETA
+ w2 * distance
+ w3 * driver_acceptance_probability
+ w4 * driver_rating
+ w5 * marketplace_balance
In practice, matching can become a sophisticated optimization problem involving supply, demand, ETA, driver preferences, pricing, and marketplace balancing.
8. Preventing Multiple Riders From Getting the Same Driver
This is a classic distributed-systems problem.
Imagine:
Rider A ──► Matching Server 1
│
▼
Driver D
Rider B ──► Matching Server 2
│
▼
Driver D
Both servers see Driver D as available.
We need an atomic operation:
AVAILABLE
│
▼
RESERVED
│
▼
ASSIGNED
For example:
SET driver:123:lock requestId NX EX 10
Or use an atomic state transition in a strongly consistent store.
If successful:
AVAILABLE → RESERVED
If another matching request attempts the same driver:
AVAILABLE → RESERVED ✓
AVAILABLE → RESERVED ✗
Only one request wins.
9. Ride State Machine
The trip lifecycle should be explicitly modeled.
┌───────────┐
│ REQUESTED │
└─────┬─────┘
│
▼
┌───────────┐
│ MATCHING │
└─────┬─────┘
│
▼
┌───────────┐
│ ACCEPTED │
└─────┬─────┘
│
▼
┌───────────┐
│ ARRIVING │
└─────┬─────┘
│
▼
┌───────────┐
│ PICKED UP │
└─────┬─────┘
│
▼
┌───────────┐
│ IN_TRIP │
└─────┬─────┘
│
▼
┌───────────┐
│ COMPLETED │
└─────┬─────┘
│
▼
┌───────────┐
│ PAID │
└───────────┘
Cancellation states should also be modeled explicitly.
This prevents invalid transitions such as:
COMPLETED → ACCEPTED
10. Database Design
A relational database is appropriate for transactional data.
Rider
rider (
id,
name,
phone,
email,
created_at
)
Driver
driver (
id,
name,
status,
vehicle_id,
rating,
created_at
)
Vehicle
vehicle (
id,
driver_id,
type,
license_plate
)
Trip
trip (
id,
rider_id,
driver_id,
pickup_lat,
pickup_lng,
destination_lat,
destination_lng,
status,
fare,
created_at,
completed_at
)
Payment
payment (
id,
trip_id,
amount,
currency,
status,
payment_provider_id,
created_at
)
11. Why Not Store Driver Locations in PostgreSQL?
Imagine:
5M drivers
÷ 3 seconds
≈ 1.67M updates/sec
That creates enormous write pressure.
More importantly, most of these writes are ephemeral.
We primarily care about:
“Where is the driver now?”
rather than:
“Where was the driver every second for the last three months?”
Therefore:
Current location
↓
Redis / distributed geo index
Historical location
↓
Kafka
↓
Data Lake / Object Storage
This separation is extremely important.
12. Kafka/Event Streaming
Use Kafka for asynchronous events:
TripCreated
DriverLocationUpdated
DriverAssigned
DriverArrived
TripStarted
TripCompleted
PaymentCompleted
DriverRated
Example:
Trip Service
│
▼
Kafka
│
┌───┼──────────────┐
▼ ▼ ▼
ETA Notification Analytics
Svc Service Pipeline
This prevents synchronous coupling.
For example, completing a trip shouldn’t require the Trip Service to synchronously call:
Payment
Analytics
Notification
Rating
Loyalty
Fraud
Instead:
TripCompleted
│
▼
Kafka
│
┌────┼────┬──────┐
▼ ▼ ▼ ▼
Pay Notify Fraud Analytics
13. Real-Time Driver Tracking
Once the driver accepts the trip:
Driver App
│
│ GPS updates
▼
Location Service
│
▼
Pub/Sub / WebSocket
│
▼
Rider App
For real-time communication:
- WebSocket
- Server-Sent Events
- Mobile push notifications
WebSocket is particularly useful when the rider needs continuous updates.
Example:
Driver
│
│ location
▼
Location Service
│
▼
WebSocket Gateway
│
▼
Rider
14. Push Notifications
Some events don’t require a persistent WebSocket connection.
For example:
Driver accepted your ride.
Use:
Notification Service
│
├──► APNs
└──► FCM
The architecture becomes:
Event
│
▼
Kafka
│
▼
Notification Service
│ │
▼ ▼
APNs FCM
│ │
▼ ▼
iPhone Android
15. Pricing System
A simplified fare formula:
Fare =
Base Fare
+ Distance × PerKmRate
+ Time × PerMinuteRate
+ Surge
+ Fees
For example:
Base = £2
Distance = £8
Time = £4
Surge = £3
----------------
Total = £17
Pricing should be calculated from a consistent pricing version.
For example:
{
"pricingVersion": "2026-08-09-v17",
"baseFare": 2.0,
"distanceRate": 1.5,
"timeRate": 0.25,
"surgeMultiplier": 1.2
}
This is important because the price shown to the rider and the final charge need to be explainable.
16. Surge Pricing
This is another interesting interview topic.
Suppose:
Demand = 10,000 riders
Supply = 2,000 drivers
We have a supply/demand imbalance.
The platform can divide a city into geographic zones:
+-----+-----+-----+
| A | B | C |
| 1.1x| 1.8x| 1.0x|
+-----+-----+-----+
| D | E | F |
| 1.2x| 2.1x| 1.1x|
+-----+-----+-----+
Each zone can calculate:
demand / supply
and update its multiplier.
However, surge pricing should be treated as a business policy service, not hard-coded into the matching service.
17. Payment Architecture
Payment should be asynchronous and idempotent.
TripCompleted
│
▼
Payment Service
│
▼
Payment Provider
│
▼
Payment Result
│
▼
Kafka
│
▼
Trip / Receipt / Notification
Use an idempotency key:
Idempotency-Key: trip-123-payment
If the request is retried:
Payment(trip-123)
Payment(trip-123)
Payment(trip-123)
the customer should only be charged once.
18. Handling Network Failures
Suppose the driver loses network connectivity.
The driver app should:
GPS
│
▼
Local Buffer
│
▼
Network available?
│
├── No ──► Store locally
│
└── Yes ─► Send batch
The server should tolerate delayed and out-of-order updates.
Every location update should include:
driverId
latitude
longitude
timestamp
sequenceNumber
The server can reject stale updates:
if timestamp < latestTimestamp:
ignore
19. Handling Kafka Duplicates
Kafka consumers may process the same event more than once.
For example:
TripCompleted
TripCompleted
Therefore consumers should be idempotent.
Use:
eventId
and maintain:
processed_events(event_id)
or use an idempotent operation.
The principle is:
At-least-once delivery + idempotent consumers is often more practical than trying to guarantee exactly-once processing everywhere.
20. Consistency Model
Not everything requires strong consistency.
Strong consistency
Use for:
- Driver assignment
- Trip state transitions
- Payment state
- Financial transactions
Eventual consistency
Use for:
- Driver location
- Analytics
- Ratings
- Search indexes
- Historical reporting
For example:
Driver GPS
↓
Eventual consistency
is perfectly acceptable.
If the rider sees:
Driver is 200m away
and one second later:
Driver is 230m away
that’s normal.
But:
£20 charged
must not become:
£40 charged
because of eventual consistency.
21. Scaling Strategy
Partition by geography
Instead of:
Global Matching Service
we can partition:
London
Manchester
New York
Paris
Tokyo
...
Conceptually:
Matching Router
│
┌───────────┼───────────┐
▼ ▼ ▼
Europe America Asia
│
┌────┼────┐
▼ ▼ ▼
London Paris Berlin
Geographic partitioning provides:
- Lower latency
- Smaller working sets
- Better fault isolation
- Easier scaling
- Localized matching
22. Handling Hotspots
Imagine a stadium after a football match.
Suddenly:
100,000 riders
↓
one geographic area
That area becomes a hotspot.
Solutions include:
Dynamic partitioning
Split a hot geographic cell:
Before:
+----------------+
| |
| HOT ZONE |
| |
+----------------+
After:
+--------+--------+
| | |
| A | B |
+--------+--------+
| | |
| C | D |
+--------+--------+
Load balancing
Route requests across multiple matching workers.
Queueing
Use Kafka or another queue to smooth traffic spikes.
Local caching
Cache:
- Driver availability
- Pricing configuration
- Map metadata
23. Availability
For a global service:
Global DNS
│
┌──────────┴──────────┐
▼ ▼
Region A Region B
│ │
┌─────┴─────┐ ┌─────┴─────┐
▼ ▼ ▼ ▼
Zone 1 Zone 2 Zone 1 Zone 2
Services should run across multiple availability zones.
If one instance fails:
Instance 1 ✗
Instance 2 ✓
Instance 3 ✓
Traffic continues.
For critical databases:
- Replication
- Automated failover
- Backups
- Disaster recovery
24. Caching
Redis can cache:
Driver location
Driver availability
Surge pricing
ETA
User session
Frequently accessed trip information
But don’t blindly cache everything.
For example:
Payment status
should have a much stronger consistency model than:
Driver location
25. API Design
Request a ride
http
POST /v1/rides
{
"pickup": {
"lat": 51.5074,
"lng": -0.1278
},
"destination": {
"lat": 51.5150,
"lng": -0.1410
},
"vehicleType": "UBER_X"
}
Response:
{
"rideId": "ride_123",
"status": "MATCHING",
"estimatedFare": 18.50
}
Driver location
http
POST /v1/drivers/{id}/location
Accept ride
http
POST /v1/rides/{rideId}/accept
Start ride
http
POST /v1/rides/{rideId}/start
Complete ride
http
POST /v1/rides/{rideId}/complete
26. End-to-End Ride Flow
This is the most important sequence to explain in an interview.
Rider
│
│ Request ride
▼
API Gateway
│
▼
Trip Service
│
│ create trip
▼
Matching Service
│
│ query nearby drivers
▼
Geo Service
│
▼
Redis Geo Index
│
│ drivers
▼
Matching Service
│
│ reserve driver
▼
Driver
│
│ accept
▼
Trip Service
│
│ DRIVER_ASSIGNED
▼
Notification Service
│
▼
Rider
│
│ real-time tracking
▼
Location Service
│
▼
WebSocket
│
▼
Rider
│
│ trip completed
▼
Trip Service
│
▼
Kafka
│
├──► Payment Service
├──► Notification Service
├──► Rating Service
└──► Analytics
27. What Are the Hardest Parts?
In an interview, explicitly identify the difficult parts.
Challenge #1: Real-time location
Millions of drivers constantly send GPS updates.
Solution:
Redis / Geo Index
+
Kafka
+
WebSocket
Challenge #2: Driver matching
Need to find suitable drivers quickly.
Solution:
Geohash / S2
+
Geo Index
+
Matching Service
Challenge #3: Double assignment
Two riders might select the same driver.
Solution:
Atomic reservation
+
Distributed locking / CAS
+
Driver state machine
Challenge #4: Payment duplication
Network retries could cause multiple charges.
Solution:
Idempotency Key
+
Payment State Machine
Challenge #5: Hot geographic zones
A stadium or airport can suddenly generate huge traffic.
Solution:
Geographic partitioning
+
Dynamic sharding
+
Autoscaling
+
Queueing
28. Technology Choices
A possible implementation:
| Component | Technology |
|---|---|
| API Gateway | NGINX / Envoy |
| Backend | Java / Spring Boot |
| Real-time | WebSocket |
| Event Streaming | Kafka |
| Cache | Redis |
| Database | PostgreSQL / MySQL |
| Geo Index | Redis Geo / S2 / specialized geo DB |
| Object Storage | S3 |
| Search | Elasticsearch/OpenSearch |
| Container | Kubernetes |
| Monitoring | Prometheus + Grafana |
| Tracing | OpenTelemetry |
| Cloud | AWS / Azure / GCP |
The important point is:
The architecture matters more than the specific technology names.
29. Observability
For a production Uber-like system, monitor:
API
Request rate
p50 / p95 / p99 latency
Error rate
Matching
Match success rate
Time-to-match
Driver acceptance rate
Location
Location update rate
Dropped updates
Stale location percentage
Trip
Cancellation rate
Trip completion rate
Infrastructure
CPU
Memory
Kafka lag
Redis latency
Database connections
A particularly useful metric is:
Ride Request
↓
Time to Driver Assignment
Because this directly measures the user’s experience.
30. Security
Important security considerations:
- OAuth/JWT authentication
- TLS everywhere
- Encrypt sensitive data
- Tokenize payment information
- Role-based access control
- Rate limiting
- Fraud detection
- Location-data privacy
- Audit logging
Location data is particularly sensitive and should have strict access controls and retention policies.
31. Final Architecture
Putting everything together:
┌──────────────┐
│ Rider / App │
└──────┬───────┘
│
┌──────▼───────┐
│ API Gateway │
└──────┬───────┘
│
┌───────────────────────┼────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Trip Service│ │ User Service │ │Payment Svc │
└──────┬──────┘ └──────────────┘ └─────────────┘
│
▼
┌──────────────┐
│ Matching │
│ Service │
└──────┬───────┘
│
▼
┌──────────────┐
│ Geo Service │
└──────┬───────┘
│
▼
┌──────────────┐
│ Redis Geo │
│ Driver Index │
└──────────────┘
Driver App
│
│ GPS
▼
Location Service
│
├──────────────► Redis
│
└──────────────► Kafka
│
┌───────────┼─────────────┐
▼ ▼ ▼
Notification Analytics Fraud
│
▼
WebSocket
│
▼
Rider
PostgreSQL
▲
│
┌─────────┼─────────┐
│ │ │
Trip User Payment
32. How to Answer This in a 45-Minute Interview
A strong interview structure is:
0–5 min — Requirements
Say:
“I’ll focus on ride requesting, driver location tracking, matching, trip lifecycle, and payment. I’ll treat ratings and some secondary features as extensions.”
5–10 min — Scale
Estimate:
10M rides/day
5M active drivers
~1.7M location updates/sec
This immediately demonstrates scale awareness.
10–15 min — High-level architecture
Draw:
API Gateway
↓
Trip → Matching → Geo
↓ ↓
Kafka Redis
15–25 min — Deep dive
Focus on:
- Geospatial indexing
- Driver matching
- Driver reservation
- Real-time tracking
25–35 min — Distributed systems
Discuss:
- Consistency
- Idempotency
- Kafka
- Failure handling
- Hotspots
- Geographic sharding
35–40 min — Reliability
Discuss:
- Multi-AZ
- Replication
- Failover
- Monitoring
- Disaster recovery
40–45 min — Trade-offs
End with:
“The key architectural trade-off is that we don’t need strong consistency everywhere. We use strong consistency for trip assignment and payments, while accepting eventual consistency for high-volume location data.”
33. The Key Interview Insight
If the interviewer remembers only one thing from your design, it should be this:
UBER
│
┌──────────┴──────────┐
│ │
Transactional Real-time
System System
│ │
▼ ▼
PostgreSQL Redis / Geo
│ │
▼ ▼
Trip/Pay Location
│ │
└──────────┬──────────┘
▼
Kafka
│
Async Event System
Uber isn’t primarily a CRUD application.
Its hardest engineering problem is the combination of:
real-time geospatial data + distributed matching + transactional trip state + massive event processing.
That’s what makes Uber an excellent Senior/Staff-level system design interview problem.