Skip to content
Bill Liao
Go back

Uber System Design Interview Question and Answer

Edit page

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:

  1. 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
  2. Driver

    • Go online/offline
    • Continuously send GPS location
    • Receive ride requests
    • Accept/reject requests
    • Navigate to pickup
    • Start/end trip
    • Receive earnings
  3. Platform

    • Match riders with nearby drivers
    • Calculate ETA
    • Calculate fares
    • Process payments
    • Send notifications
    • Maintain trip history

Non-Functional Requirements

The system should provide:


2. Back-of-the-Envelope Estimation

Assume:

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:

ServiceResponsibility
API GatewayAuthentication, routing, rate limiting
User ServiceRider/driver profiles
Driver ServiceDriver status and availability
Location ServiceReal-time GPS updates
Geo ServiceNearby-driver queries
Matching ServiceRider ↔ driver matching
Trip ServiceTrip lifecycle
Pricing ServiceFare calculation
Payment ServicePayment processing
Notification ServicePush/SMS notifications
Rating ServiceDriver/rider ratings
ETA ServiceRoute and ETA calculation
Fraud ServiceFraud detection
Event ServiceAsync 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 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:

Eventual consistency

Use for:

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:


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:


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:


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:

ComponentTechnology
API GatewayNGINX / Envoy
BackendJava / Spring Boot
Real-timeWebSocket
Event StreamingKafka
CacheRedis
DatabasePostgreSQL / MySQL
Geo IndexRedis Geo / S2 / specialized geo DB
Object StorageS3
SearchElasticsearch/OpenSearch
ContainerKubernetes
MonitoringPrometheus + Grafana
TracingOpenTelemetry
CloudAWS / 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:

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:

  1. Geospatial indexing
  2. Driver matching
  3. Driver reservation
  4. Real-time tracking

25–35 min — Distributed systems

Discuss:

35–40 min — Reliability

Discuss:

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.


Edit page
Share this post:

Previous Post
130 Most Popular LeetCode Problems and Answers
Next Post
Airbnb System Design Interview Question and Answer