Skip to content

Food Delivery (DoorDash / Swiggy / Uber Eats)#

Problem statement (interviewer prompt)

Design DoorDash / Swiggy / Uber Eats: customers order from local restaurants, the system matches a nearby driver, the driver picks up + delivers, and everyone sees a live ETA. Cover restaurant search, dispatch / matching, live tracking, and surge pricing.

flowchart LR
  U([Customer])
  R[Restaurant App]
  D([Driver App])
  ORD[Order Service]
  DISP[Dispatch / Matching]
  GEO[Geo Index]
  PAY[Payment]
  U --> ORD --> PAY
  ORD --> R
  ORD --> DISP --> D
  D --> GEO
  DISP --> GEO

    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 U,D client;
    class R,ORD,DISP,GEO,PAY service;
flowchart TB
  subgraph Apps[Apps]
    CUST([Customer])
    REST[Restaurant]
    DRV([Driver])
  end

  subgraph Edge
    CDN
    GW
    WS[WebSocket gateway]
  end

  subgraph Discover[Discovery]
    MENU[Menu / Catalog]
    SRCH[Search]
    REC([Recommend])
    SLA[Promised ETA estimator]
    GEOS[Geo serviceability]
  end

  subgraph Order
    ORDSVC[Order Service]
    ODB[(Orders)]
    SAGA([Order saga])
  end

  subgraph Restaurant_Side[Restaurant Side]
    TAB[Tablet / KDS]
    PREP[Prep time tracker]
  end

  subgraph Dispatch[Dispatch / Matching]
    DSVC[Dispatch Service]
    GIDX[(Geo index<br/>geohash / S2)]
    DRVPRE([Driver presence])
    SCORE[Pickup score<br/>distance + cooking time + ratings]
    ASSIGN[Assignment]
    BATCH[Batching multi-orders]
  end

  subgraph Live[Live tracking]
    LOC([Location ingest<br/>500ms-3s])
    ETA[Live ETA]
    GEOFENCE[Geofence events]
  end

  subgraph Pay
    PAYSVC[Payment Service]
    GTW((Payment provider))
    PROMO[Coupons]
    WAL[Wallet]
  end

  subgraph Notif
    PUSH[Push]
    SMS[SMS]
    INAPP[In-app]
  end

  subgraph Pricing[Pricing / Surge]
    BASE[Base fare]
    SURGE[Surge / demand-supply]
    BG[Background pricing]
  end

  CUST --> CDN --> GW
  GW --> Discover
  GW --> Order
  Order --> Restaurant_Side
  Order --> Dispatch
  Dispatch --> Live
  Live --- DRV
  DRV --> WS --> Live
  Order --> Pay
  Order --> Notif
  Pricing --- Order

    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 CUST,DRV,DRVPRE client;
    class WS edge;
    class REST,MENU,SRCH,SLA,GEOS,ORDSVC,TAB,PREP,DSVC,SCORE,ASSIGN,BATCH,ETA,GEOFENCE,PAYSVC,PROMO,WAL,PUSH,SMS,INAPP,BASE,SURGE,BG service;
    class ODB,GIDX datastore;
    class REC,SAGA,LOC compute;
    class GTW external;

Dispatch logic#

  • New order → query geo index for online drivers near restaurant.
  • Score candidates: distance, prep time, driver rating, idle time, batch potential.
  • Assign top candidate; if reject, fall through next.
  • Multi-order batch when along the same route (5-15 min detour OK).

Live location plane#

  • Driver app sends location every 1-3 s (faster near pickup/drop).
  • Geo index sharded by geohash prefix; updates are write-heavy.
  • Customer subscribes to driver's WS channel for live ETA.

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 LSM vs B-Tree engines WAL, memtable, SSTables, compaction storage-engines-lsm-btree
HLD Distributed transactions 2PC, TCC, sagas, outbox/inbox distributed-transactions
HLD Realtime protocols WS / SSE / polling / gRPC streaming realtime-protocols
HLD Geo indexing Geohash, Quadtree, S2, H3, R-tree geo-indexing
LLD REST API design verbs, statuses, pagination, errors rest-api-design
LLD Async models futures / async-await / coroutines / actors async-models

Quick reference#

Functional#

  • Restaurant search, menu, order.
  • Real-time dispatch to drivers; live tracking; ETA.
  • Payment, refunds, support.
  • Promotions, ratings.
  • Restaurant operations (KDS / prep time).

Non-functional#

  • Order placement p99 < 1 s.
  • Live location updates < 3 s lag.
  • City-scale matching < 10 s.
  • 99.9% availability for ordering.

Capacity#

  • 100M+ orders/month for one big platform.
  • Peak hours: thousands of orders/min per city.
  • Active drivers: 100k+ per city.

Schema#

  • orders(id, customer_id, restaurant_id, items[], status, totals, driver_id, ETAs)
  • drivers(id, status, current_loc, vehicle, ratings)
  • presence(driver_id, geohash, ts) Redis geo or KV with TTL
  • restaurants(id, geo, hours, prep_time)

Trade-offs#

  • Centralized matcher simpler but capped by single machine; geo-sharded matcher scales but cross-shard handoffs.
  • Batching improves driver utilization but harms ETA reliability.
  • Surge pricing balances supply/demand but UX/regulatory issues.

Refs#

  • DoorDash, Uber Eats, Swiggy engineering posts on dispatch + ETA models.
  • "Uber: Real-time dispatching" KDD papers.
  • ByteByteGo "Design DoorDash / Uber Eats".

FAQ#

How does a food delivery app match drivers to orders?#

A dispatch service queries the geo index for nearby drivers, then ranks them by ETA to the restaurant, current load, and route compatibility with adjacent orders for batching.

How is delivery ETA estimated?#

ETA combines restaurant prep time, driver to restaurant travel, food handoff, and driver to customer travel. Each leg is predicted with an ML model trained on historic completion data.

How does the geo index update with thousands of drivers?#

Driver apps push location every 1 to 3 seconds. Updates land in a geohash or H3 indexed store like Redis with TTL, sharded by cell so hot urban cells stay manageable.

How does surge pricing work in food delivery?#

When demand outstrips supply in a region, a multiplier is applied to delivery fees. It raises incentives for drivers to move into the region and gently dampens demand.

How do food delivery apps support order batching?#

The dispatcher looks for orders going from nearby restaurants to nearby drop offs. Batching is bounded by max detour and freshness constraints so customers do not see cold food.

Further reading#

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

Video walkthrough

System Design: Design Zomato / Swiggy / Uber Eats / DoorDash : via Mock Interview