How 10-minute delivery apps really work (system design)
It's 7:02 AM. You place a grocery order, and the app says 8 minutes. The big supermarket is 3 km away, yet the doorbell rings at 7:10.
The rider didn't break any speed limits. The speed was designed into the system before you even opened the app. Here is how, and how to explain it in a system design interview.
The core insight: delivery speed comes from distance, not from how fast the rider drives. Every design choice below exists to keep the distance and the waiting short.
1. Dark stores: shrink the distance
A dark store is a small warehouse, usually 1,500-4,000 sq ft, that serves online orders only. No walk-in customers, no fancy aisles. Each one covers a radius of roughly 1-2 km.
- Short radius → ride time of 3-5 minutes
- Layout optimised for pickers, not shoppers: fast movers near the packing desk
- A limited range (a few thousand SKUs) keeps the store small and the stock accurate
Trade-off: you need many small stores rather than a few big ones. That means higher real-estate and operations cost, and every store has to be stocked correctly.
2. Demand forecasting: stock before you ask
A small store can't hold everything, so it has to hold the right things. Overnight, forecasting models predict demand per store, per SKU, per hour, using:
- historical orders for that area and day of week
- weather, holidays, festivals, local events
- recent trends and promotions
The output drives replenishment: trucks restock each dark store before the morning rush. Bread, milk and eggs are on the shelf by 6 AM because the system expected your order.
Interview angle: this is a batch ML pipeline (data lake → feature store → model → replenishment orders), separate from the real-time ordering path.
3. Geo-sharding and nearest-store routing
The city map is divided into grid cells (for example geohash or H3 hexagons). Every cell is assigned to one serviceable dark store.
When you open the app:
- Your lat/long → cell ID (a cheap computation)
- Cell ID → store ID (a key-value lookup)
- Every later request is routed with that store ID
This is geo-sharding: data and traffic are partitioned by location. Orders, inventory and rider assignment for one store mostly stay inside that shard, so the system scales horizontally by adding stores and shards. Cells can be reassigned dynamically when a store is overloaded or closed.
4. Inventory sync: show only what's really there
The app shows only the live stock of your assigned store. If the store has 0 units of something, you shouldn't be able to add it to your cart.
- Every pick, restock and damage write-off updates inventory in near real time (event stream such as Kafka → inventory service)
- At checkout, items are reserved atomically (decrement with a check, or a short-TTL reservation) to avoid overselling
- Unpaid or abandoned reservations expire and the stock is released
Trade-off: browsing can tolerate slightly stale counts (eventual consistency), but checkout must be strongly consistent for each SKU and store.
5. Caching: make the app open instantly
Catalog data (names, images, categories) changes rarely; prices change a few times a day. So:
- CDN for images and static assets
- Redis / in-memory cache for catalog and price data per store
- Cache invalidation driven by events when a price or listing changes
- Only fast-changing data (stock, ETA) is fetched live
The result: the home screen renders in milliseconds, and the database isn't hit by millions of identical reads.
6. The last 2 minutes: pick, pack, dispatch
- The order is pushed to the store's picker app with an optimised pick path
- Pick and pack takes about 2 minutes
- A rider is already waiting at the store, assigned by a dispatch service that knows rider locations and the order queue
- ETA = pick time + ride time, predicted per order and shown to the user
Timeline: about 1 min to confirm, 2 min to pick and pack, 4-5 min to ride = about 8 minutes.
How to answer "Design a 10-minute delivery system" in an interview
- Clarify: city scale, number of SKUs, peak orders per minute, the SLA (10 minutes at p90?)
- Core idea: speed = short distance + no waiting, so dark stores within 1-2 km
- Components:
- Location service: geo-sharding (geohash/H3) → nearest-store routing
- Catalog service + cache (CDN, Redis)
- Inventory service: event-driven sync, atomic reservation at checkout
- Order service → picker app → dispatch/rider service
- Forecasting + replenishment pipeline (batch, overnight)
- Data and consistency: eventual for browsing, strong for checkout per SKU and store
- Scale and failure: shard by store/region, reassign cells on overload, graceful degradation (hide the 10-minute promise and show a longer ETA)
- Metrics: order-to-door p50/p90, pick time, stock-out rate, forecast accuracy
One-line summary: dark stores, demand forecasting, nearest-store routing, inventory sync and caching.
Preparing for Cloud / DevOps / SRE interviews?
I've spent 14+ years building and running cloud systems. Book a Free 15-min Cloud & DevOps Interview Guidance Call: topmate.io/cloudtechbydevang
Watch the short story version on Instagram: @cloudtechbydevang
About the author
- I help engineers learn cloud, DevOps, SRE and AI in simple English, crack interviews and follow clear roadmaps. 14+ years building and running platforms on AWS, GCP, Kubernetes and Terraform. One topic a day.
Comments
Join the discussionNo comments yet. Be the first to comment.
