Designing the three-sided marketplace (customer, restaurant, delivery partner) behind a food delivery app — real-time order state, delivery partner matching/dispatch, live location tracking, and ETA estimation, built on the same geospatial and matching primitives as Uber / Ride Sharing.
Published September 23, 2026
Design a food delivery platform coordinating three distinct parties in real time — customers placing orders, restaurants preparing them, and delivery partners transporting them — from order placement through live tracking to delivery confirmation.
Functional: browse restaurants/menus, place an order, track order status in real time (placed → confirmed → preparing → picked up → delivered), match the order to a nearby available delivery partner, show live delivery-partner location to the customer. Non-functional: order-status updates must reach the customer within seconds; delivery partner matching must be fast (dispatch delay directly hurts food quality — cold food is a real, measurable outcome of slow matching); handle a geographically distributed, highly time-varying load (lunch/dinner rush hours).
Customer ──places order──▶ [Order Service]
│
Restaurant ◀──notified, confirms──┤
│
Delivery Partner ◀──dispatched────┘
│
all three parties see order status updates in real time
Unlike a typical two-sided system (buyer/seller), this design has to coordinate three independent, real-world actors whose actions are only loosely under the platform's control — a restaurant might take longer than expected to prepare food, a delivery partner might be delayed by traffic — and the order state machine has to represent and gracefully handle this uncertainty, not assume a clean linear happy path.
This reuses the same core geospatial matching problem as Uber / Ride Sharing directly: finding nearby AVAILABLE delivery partners for a given restaurant location, using a geospatial index (geohashing or a quadtree, as covered in that lesson) rather than scanning every partner's location. The matching decision here additionally factors in the restaurant's current food-prep time estimate — dispatching a delivery partner to arrive exactly as the food is ready (not too early, sitting idle, and not too late, letting food go cold) is a genuinely harder optimization than ride-sharing's simpler "nearest available driver" matching, since it has to jointly consider two independent timelines (food prep AND partner travel time).
[Delivery Partner App] → periodically pushes GPS location (e.g. every 5-10 sec)
→ [Location Service] → updates the order's tracking data
→ pushed to [Customer App] via WebSocket / long-polling (not the customer polling
a REST endpoint repeatedly — see Notification Service's push-delivery patterns)
Both order-status transitions (order confirmed, food being prepared, picked up) and live GPS location updates need to reach the customer with low latency — a persistent connection (WebSocket) or a push-notification-based update pattern is the standard approach, directly reusing Notification Service's real-time delivery infrastructure rather than requiring the customer's app to poll repeatedly (wasteful, and adds latency to how fresh the displayed location is).
ETA (estimated arrival time) shown to the customer combines multiple independently-estimated segments: remaining food-prep time (from the restaurant, sometimes a static average, sometimes dynamically adjusted based on the restaurant's current order volume), delivery-partner travel time TO the restaurant, and delivery-partner travel time FROM the restaurant to the customer (typically using a routing/maps service factoring current traffic conditions) — the combined estimate is necessarily approximate, and a strong design should communicate a RANGE or update the estimate as more accurate information becomes available (e.g. once the order is actually picked up, the ETA can tighten considerably since one major source of uncertainty — prep time — has resolved).
Q: What happens if a matched delivery partner cancels or goes offline mid-delivery? A: The system needs an explicit re-dispatch path — detecting the partner's unavailability (via a heartbeat/location-update timeout, similar to Health Checks' liveness concept applied to a mobile client) and re-running the matching process for a new nearby partner, ideally without the customer needing to be told anything went wrong beyond a possibly-updated ETA.
Q: How would you handle a restaurant that's overloaded and can't realistically prepare an order in a reasonable time? A: This argues for a restaurant-side capacity signal (an estimated queue/prep-time that grows as the restaurant accumulates concurrent orders) feeding BACK into whether the restaurant should even appear as available for new orders during that period — order placement and dispatch decisions should account for real restaurant capacity, not just menu availability.
Q: Why might food delivery's matching algorithm need to be more sophisticated than 'assign the closest available partner,' unlike simpler ride-sharing matching? A: Because the optimal partner isn't just about the partner's current distance to the restaurant — a delivery partner who's slightly farther away but will arrive exactly as food finishes cooking is often the BETTER match than the nearest partner who'd sit waiting for 15 minutes, so the matching function needs food-readiness time as a genuine second input, not just partner distance.
Q: How does peak lunch/dinner-hour load specifically stress this design differently from steady-state load? A: Delivery-partner supply and order demand are both highly time-correlated (everyone orders lunch around the same 90-minute window) — unlike many systems where load is relatively smooth, this creates a genuine, predictable supply/demand imbalance the matching and dispatch system has to handle explicitly (e.g. surge-style incentives to bring more partners online, or realistic ETA inflation during the rush rather than an ETA promise the system can't actually keep).