Skip to content

Uber / Lyft / Ola#

Problem statement (interviewer prompt)

Design Uber / Lyft: riders request rides, the system finds a nearby driver in seconds, computes fare with surge, tracks the trip live, and charges on completion. Handle 10M+ rides/day, location pings every 1-3s, and dispatch decisions in <5s.

flowchart LR
  R([Rider])
  D([Driver])
  DISP[Dispatch]
  GEO[Geo Index]
  PRICE[Pricing / Surge]
  PAY[Payment]
  R --> DISP --> D
  D --> GEO
  DISP --> GEO
  DISP --> PRICE
  R --> PAY

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class R,D client;
    class DISP,GEO,PRICE,PAY service;
flowchart TB
  subgraph Apps
    RAPP([Rider app])
    DAPP([Driver app])
  end

  subgraph Edge
    CDN
    LB
    GW[Edge gateway<br/>per-region]
    WS[WebSocket]
  end

  subgraph Geo[Geo Indexing - hot path]
    LOC([Location Ingest])
    GIDX[(Driver presence<br/>S2 cell / geohash)]
    AVAIL([Available drivers per cell])
    ETA1([Ego-driver ETA estimator])
  end

  subgraph Dispatch[Dispatch / Matching]
    DSVC[Dispatch Service]
    POOL[Candidate pool fetch]
    SCORE[Score: distance, ETA, ratings, surge]
    OFFER([Offer to driver - 15s])
    BATCH[Batch / pool rides]
  end

  subgraph Pricing
    BASE[Base fare]
    SURGE[Surge model]
    EST[Trip estimate]
  end

  subgraph Trip
    LIFE[Trip lifecycle SM]
    NAV[Nav + route]
    TKM([Telematics ingest])
    RECEIPT[Receipt + tax]
    PAYSVC[Payment]
    PG((Payment provider))
  end

  subgraph Safety
    BG[Background checks]
    PIN[Trip PIN]
    SOS[Emergency / panic]
  end

  subgraph Data
    KAFKA[[Kafka event bus]]
    FS[Feature store]
    ML[ML platform]
    OBS[Metrics / traces]
  end

  RAPP --> CDN --> LB --> GW
  DAPP --> LB
  DAPP --> WS --> LOC --> GIDX
  RAPP --> Dispatch
  Dispatch --> Geo
  Dispatch --> Pricing
  Dispatch --> Trip
  Trip --> PAYSVC --> PG
  Trip --> KAFKA
  Geo --> KAFKA --> FS --> ML
  ML --> Pricing
  Safety --- Trip
  OBS --- Dispatch

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class RAPP,DAPP,AVAIL,ETA1,OFFER client;
    class GW edge;
    class WS,DSVC,POOL,SCORE,BATCH,BASE,SURGE,EST,LIFE,NAV,RECEIPT,PAYSVC,BG,PIN,SOS,ML service;
    class GIDX,FS datastore;
    class KAFKA queue;
    class LOC,TKM compute;
    class PG external;
    class OBS obs;

Geo index#

  • Driver location every 1-3 s → server.
  • Index sharded by S2 cell ID; updates write-heavy.
  • Active drivers stored in Redis-like KV with (driver_id, cell, ts); TTL purges stale.

Dispatch algorithm#

  1. Customer requests ride at point P.
  2. Geo lookup returns drivers in expanding S2 ring around P.
  3. Score each candidate (ETA + last assignment time + ratings).
  4. Offer to top driver; 15 s timeout; on reject, next.
  5. Update driver presence → unavailable on accept.

Surge pricing#

  • Per S2 cell × minute: demand/supply ratio.
  • Multiplier applied at quote time; shown to user before confirm.

Trip lifecycle#

  • States: REQUESTED → DRIVER_ASSIGNED → EN_ROUTE → ARRIVED → IN_PROGRESS → COMPLETED / CANCELLED.
  • Each transition emits an event; finance + analytics consume.

Glossary & fundamentals#

Concepts referenced in this design. Each row links to its canonical page; the tag column shows whether it is a high-level (HLD) or low-level (LLD) concept.

Tag Concept What it is Page
HLD CDN edge caching for static assets cdn
HLD Sharding horizontal partitioning across nodes database-sharding
HLD Pub/Sub & message brokers topics, consumer groups, delivery semantics pub-sub-pattern
HLD Observability metrics, logs, traces, SLOs observability
HLD Realtime protocols WS / SSE / polling / gRPC streaming realtime-protocols
HLD Geo indexing Geohash, Quadtree, S2, H3, R-tree geo-indexing

Quick reference#

Functional#

  • Request ride, match driver, compute fare.
  • Live tracking, ETA.
  • Pay, rate, tip.
  • Surge pricing.
  • Driver onboarding, payouts.

Non-functional#

  • Dispatch decision < 5 s.
  • Driver location lag < 3 s.
  • 99.99% on hot path.

Capacity#

  • Millions of active drivers globally.
  • 10M+ rides/day.
  • Location ingests: millions/s peak.

Schema#

  • drivers(id, status, vehicle, ratings)
  • presence(driver_id, cell, lat, lng, ts) Redis Geo / KV
  • trips(id, rider_id, driver_id, pickup, drop, fare, status_history[])
  • payments(...)

Trade-offs#

  • Centralized matcher simpler but bottleneck → matcher sharded by city / region.
  • Eventual presence consistency is fine; double-assign protected by atomic update.
  • Surge balances supply/demand but unpopular; cap and explain.

Refs#

  • Uber Engineering blog (Schemaless, Ringpop, Cadence, M3, H3 hex grid).
  • Lyft engineering (Envoy origin) blog.
  • ByteByteGo "Design Uber", Alex Xu Vol 2.

FAQ#

How does Uber match riders to nearby drivers in seconds?#

Drivers stream GPS pings to a geo-sharded index like S2 or H3. When a rider requests, the dispatcher queries the cell, scores candidates by ETA and acceptance probability, and offers the trip.

How does Uber handle 10 million rides per day at scale?#

Services are sharded by city or region so most traffic stays local. Dispatch, pricing, payments, and trip state run as independent microservices behind their own data stores.

How does surge pricing work?#

When demand exceeds supply in a cell over a short window, a multiplier raises the price. Higher pay attracts drivers from adjacent cells and gently discourages low priority trips.

How does Uber track an active trip in real time?#

The driver app pushes location every 1 to 3 seconds via WebSocket. A trip state machine updates ETA, route, and milestones. The rider subscribes to the same channel for live updates.

How are payments charged after a trip ends?#

Trip cost is computed from time, distance, surge, and tolls. The payment service authorizes and captures asynchronously with idempotent retries, then triggers receipts and driver payouts.

Further reading#

Curated, high-credibility sources for going deeper on this topic.

Video walkthrough

System Design Interview: Design Uber : via Hello Interview