Ride sharing backend architecture.
Every driver streams their position every few seconds whether or not anyone is riding, which makes this one of the few consumer systems where writes dominate reads.
The components
Every row below is read from the graph that produced the diagram above, so the two cannot disagree.
| Component | Tier | Why it is there |
|---|---|---|
| Rider app | Client | Supporting component |
| Driver app | Client | Streams location every few seconds |
| API gateway | Edge | Supporting component |
| Location ingest | Application | Highest write volume in the system |
| Matching engine | Application | Geospatial index, not a table scan |
| Trip service | Application | Supporting component |
| Pricing | Application | Surge from live supply and demand |
| Payments | Application | Supporting component |
| Redis geo | Data | Driver positions, short TTL |
| Postgres | Data | Supporting component |
| Kafka | Data | Supporting component |
| Maps & routing | External | Supporting component |
Design decisions worth arguing about
A diagram shows what was chosen. It does not show what it cost, and that is usually the part that matters in a review or an interview.
Location writes get their own path
Driver pings are constant, high volume and individually worthless: only the latest one matters. Routing them through the same service that handles trip state would swamp a store that needs to be durable and transactional with writes that need neither. Separating them lets locations live in an in-memory geospatial index with a short TTL while trips live in Postgres. The cost is two stores holding related data and a window where a driver's position and their trip state disagree.
A geospatial index, not a query over every driver
Finding nearby drivers by scanning and computing distance does not survive contact with a real city. Indexing positions into cells means matching reads a handful of buckets rather than the whole fleet. The tradeoff is at the boundaries: a driver just across a cell edge can be nearer than one inside it, so you have to search neighbouring cells too, and cell size becomes a tuning parameter trading accuracy for work.
Surge is a feedback loop, so it needs damping
Pricing from live supply and demand is the point, but a price that reacts instantly oscillates: it spikes, drivers move in, it collapses, they leave, it spikes again. Smoothing over a window and capping the rate of change makes it stable and makes it lag, which means the price is always slightly wrong. Stable and slightly wrong is much better than accurate and oscillating, both for drivers and for regulators.
The maps provider is a dependency you cannot replace quickly
Routing and ETAs come from outside, and both matching quality and the rider experience depend on them. That means an external rate limit is one of your capacity limits and an external outage is a partial outage for you. Caching routes between common points and degrading to straight-line distance when the provider is unavailable are unglamorous and are what keep the product usable during someone else's incident.
How it changes with scale
Location ingest grows with active drivers and is the dominant cost long before trip volume matters. Matching is naturally partitioned by geography, which is convenient: cities are independent, so scaling is mostly a matter of adding regions rather than making any one of them larger. Peak is intensely local, since demand concentrates around specific places and times.
Where it breaks first
Supply collapse in one area. When drivers are scarce, matching searches wider and wider, each search costs more, and the requests that do match produce long pickup times that cause cancellations, which put those riders back into the queue. The load rises exactly when the system is least able to satisfy it, so a search radius cap and an honest no-drivers-available response are what stop it spiralling.
Draw this yourself
Open the Diagram tab and describe the system. The agent emits a semantic graph rather than coordinates, so you can edit the components and the layout re-solves instead of drifting.
When the shape is right, Implement in code turns the canvas into a markdown specification, every component, every relationship and the notes, and starts a real turn in the Code tab with it.
Questions about this design
Why Redis rather than PostGIS for driver locations?
Because the data is ephemeral and the access pattern is a radius query against constantly changing points. An in-memory index with TTL fits that exactly. PostGIS is the better choice for geography that persists and needs to be joined against other tables.
How often should drivers report their location?
Often enough that matching is accurate, rarely enough that phones survive a shift. Every few seconds while carrying a passenger and less frequently when idle is the usual compromise, since an idle driver's exact position matters much less.
How do you prevent two riders matching the same driver?
A short lock on the driver during the offer window, released on decline or timeout. Without it, two matching workers can offer the same driver simultaneously and one rider gets a confirmation that is then revoked.
What happens when a driver goes offline mid-trip?
The trip continues, since trip state does not depend on location. The rider loses live tracking, which is a degraded experience rather than a failure, and the trip completes from the driver's app when connectivity returns.
More templates
- Video Streaming System DesignAround ninety-nine percent of the bytes never touch your servers, which means most of this design is about preparing files so the CDN can do the work.
- Social Media Feed System DesignFan-out on write is the right answer until someone with ten million followers posts, and the entire design exists to handle that exception.
- Web Crawler System DesignThe engineering problem is not fetching pages quickly. It is fetching them politely, at scale, without visiting the same content a thousand times.
- Search Autocomplete System DesignThis is a latency problem wearing a search problem's clothes: past about a hundred milliseconds users have already typed the next character and your response is worthless.
Last updated