Design maps and navigation
Show anyone a map of anywhere, find the fastest way from A to B across a continent in well under a second, and keep the arrival time honest as traffic changes. Three hard parts hide in that sentence: a graph with hundreds of millions of road segments, a stream of millions of location pings a second, and a prediction (the ETA) that users check against reality every time.
1. The prompt
"Design a maps app: people can look at the map, get driving directions with an arrival time, and be guided turn by turn, with the route updated when traffic changes."
What makes it hard:
- Routing is a graph search on a huge graph. The textbook algorithm explores millions of intersections for a long trip; users expect an answer in a fraction of a second.
- The graph's weights change every minute. Travel times depend on live traffic, which comes from the users themselves.
- The map itself is enormous and must load instantly at every zoom level, anywhere in the world.
2. Frame the problem
Which modes: driving, walking, cycling, public transport?
Driving first. Walking and cycling later; public transport is out of scope.
Driving routes depend on live traffic; transit is a timetable problem with different algorithms. One mode keeps the design focused.
Whole world, or one country?
Whole world.
The road graph can't sit on one machine's search in reasonable time, and data has to live near users: regions and partitioning become central.
How many users?
About 1 billion monthly users; at peak around 10 million people are navigating at once.
Navigating phones send location every few seconds: that stream, not route requests, is the biggest write load.
Must routes use live traffic?
Yes, and arrival times should be accurate: within about 10% for most trips.
Live traffic means edge weights change constantly, which rules out routing structures that take hours to rebuild.
Should a route update while I'm driving?
Yes: reroute if you miss a turn or a faster route appears.
Navigation is a long-lived session, not a single request: the server needs a channel back to the phone.
Does it need to work with a poor connection?
It should keep guiding you through tunnels and dead zones.
The phone must hold the route and the map tiles for it locally; the server is an advisor, not a remote control.
Search for places too?
Basic search by name and address, yes. Reviews and photos, no.
Geocoding (text → coordinates) is a search index plus geohash cells (Module 12); keep it small.
Privacy rules for location data?
Traces must not identify people; keep them only as long as needed.
Traffic needs speeds per road, not who drove where: aggregate and drop identities early.
3. What it must do
- A user can view the map anywhere, panning and zooming smoothly.
- A user can get a driving route from A to B with an arrival time, using current traffic.
- A user can navigate: follow the route turn by turn, with rerouting when they leave it or traffic changes.
Not now: public transport (a timetable problem), reviews and photos (a separate content system), Street View imagery (a blob pipeline), offline downloads of whole regions (a follow-up in section 10).
4. How well it must do it
| Target | Why this number |
|---|---|
| Map tiles: p99 under 200 ms anywhere speed · where it runs | Panning must feel instant; slow tiles are the first thing users notice. |
| Routes: p99 under 1 s, even across a continent speed | Users tap "Directions" and wait; a second is the ceiling. |
| ETA accuracy: within 10% of the real trip time for 90% of trips data quality | The ETA is the product's promise; users compare it with reality. |
| Traffic freshness: a new jam affects routes within 2 minutes load shape | Routing into a jam that started five minutes ago is the failure users remember. |
| Navigation keeps working through server or network trouble surviving failures | A driver mid-trip can't be left without directions. |
| Location privacy: no stored trace identifies a person security and privacy | Location history is among the most sensitive personal data. |
5. Numbers that change the design
| Quantity | Working | → so we… |
|---|---|---|
| Road graph | Hundreds of millions of intersections and road segments worldwide; a continent alone is tens of millions | Plain Dijkstra on a long trip explores millions of nodes (seconds) → so we precompute shortcuts and answer in milliseconds |
| Map tiles | Zoom level z has 4z tiles; at z = 18 that's about 69 billion | Most are ocean or never viewed → so we pre-build low zooms, build high zooms on demand, and cache everything at the CDN |
| Location pings | 10 M navigating phones × 1 ping every 5 s | ~2 M pings a second → so ingestion is a partitioned stream, aggregated per road segment per minute, never a database write per ping |
| Route requests | ~100 M routes a day ÷ 10⁵ ≈ 1,000/s, ~5,000/s at peak | Modest → so a few hundred routing servers holding the graph in memory are enough; the cost is per query, not the count |
Skip estimating place-search traffic: it's an ordinary search index (Module 12) and won't change the design.
6. The nouns
- Road segment (an edge) and intersection (a node): the routing graph.
- Tile: a square of the map at one zoom level.
- Place: a named point (address, business).
- Route: a path, its geometry, steps and ETA.
- Trip: one navigation session.
- Location ping and segment speed: the raw input and the aggregate traffic.
segments segment_id, from_node, to_node, length_m, road_class, speed_limit, one_way, cell_id segment_speed segment_id, minute, avg_speed_kmh, sample_count (live, per minute; history by time of week) tiles z, x, y, version → object key in blob storage (served through the CDN) trips trip_id, user_id, route_id, started_at, status (short-lived; no raw trace stored)
7. The contract
REST for one-off requests, a streaming connection for navigation. The user comes from the auth token.
GET /v1/tiles/{z}/{x}/{y}.mvt?v={version} → vector tile (cached at the CDN for days)
GET /v1/places?q=&near=lat,lng → [{place_id, name, lat, lng}]
POST /v1/routes {origin, destination, depart_at?, avoid?}
→ {routes: [{route_id, polyline, distance_m, eta_s, steps: [...]}]} (best + up to 2 alternatives)
POST /v1/trips {route_id} → {trip_id}
WS /v1/trips/{trip_id}/stream client → {lat, lng, speed, heading, ts} every ~5 s
server → {eta_s} | {reroute: {route}} | {alert}
Data flow for traffic: phones send pings → ingestion → a stream partitioned by region → snap each ping to a road segment → average speed per segment per minute → new edge weights for routing → better routes and ETAs.
8. First working version
A CDN and tile store, a place search index, one routing service holding a region's graph in memory, and a navigation service.
8.1 Viewing the map
The app asks for the tiles covering the screen. Tiles are pre-built and stored as objects (Module 10); the CDN answers almost every request. Vector tiles carry roads and labels as data, so the phone draws them at any rotation and style.
8.2 Getting a route
Geocode the destination, then run a shortest-path search on the road graph, where each segment's weight is its travel time. The first version runs A* (Dijkstra guided towards the destination) on the region's graph in memory.
8.3 Navigating
The phone downloads the route and the tiles along it, then guides the driver locally. Every few seconds it streams its position; the server compares it with the route and recomputes the ETA.
9. Make it hold up
9.1 Fast routes on a continental graph routes under 1 s
| Approach | Why | |
|---|---|---|
| ✗ Bad | Dijkstra over the whole graph for every request | Explores in all directions: millions of nodes for a long trip, seconds of CPU per route. |
| ~ Good | A* or bidirectional search | Searches towards the target (or from both ends), several times fewer nodes. Still too slow coast to coast. |
| ✓ Great | Precomputed shortcuts: contraction hierarchies or multi-level partitions. Offline, add "shortcut" edges that skip minor roads; a query then climbs from local streets to highways and back down, touching only hundreds to thousands of nodes | Milliseconds per route. The catch: classic contraction hierarchies take a long time to rebuild when weights change, so traffic needs the variant in 9.3. |
This is the move interviewers look for: trade offline preprocessing for fast queries, the same idea as an index. Open-source engines (OSRM, Valhalla) and the Customizable Route Planning work from Microsoft Research show it works at continental scale.
9.2 Splitting the world routes under 1 s · surviving failures
- Partition the graph into cells (cities or regions) with few boundary nodes between them. Inside each cell, precompute the travel time between every pair of its boundary nodes.
- A long route searches only the start cell, the destination cell, and the small overlay graph of boundary nodes in between.
- Routing servers are sharded by region and replicated; a request for a trip inside one region goes to that region's servers. Cross-region trips use the overlay, which is small enough to replicate everywhere.
9.3 Live traffic from location pings traffic within 2 minutes · privacy
- Ingest ~2 M pings a second into a stream partitioned by region (Module 18). Strip user IDs at the edge; keep only a short-lived trip token.
- Map matching: GPS is noisy (tens of metres); snapping a sequence of points to the most likely road segments uses a hidden Markov model (Newson and Krumm, 2009).
- Aggregate speeds per segment per minute in a stream processor (Module 23), dropping segments with too few samples so no single car is identifiable.
- Update weights without a rebuild: keep the partition fixed and only redo each cell's small boundary table ("customisation") when its speeds change: seconds, not hours.
9.4 Honest arrival times ETA within 10%
| Approach | Why | |
|---|---|---|
| ✗ Bad | Distance ÷ speed limit | Ignores traffic lights, turns and congestion; always optimistic. |
| ~ Good | Live speeds per segment, summed along the route | Right now, but wrong for a 2-hour trip: by the time you reach the far segment, its traffic has changed. |
| ✓ Great | Live speeds near you, historical speeds by time of week further away, corrected by a learned model trained on completed trips | Predicts the traffic you'll meet when you get there. Measure error per region and road type every day. |
9.5 Navigation sessions and rerouting keeps working
- The phone navigates locally with the route and tiles it already has, so a tunnel or a server blip doesn't interrupt guidance.
- Off-route: the phone notices first and asks for a new route from its position.
- Better route: the server periodically re-checks active trips against new traffic and pushes a reroute only if it saves meaningful time (say 2+ minutes), to avoid flip-flopping.
- Spread the load: sending every car down the same side street creates the next jam; routing for many trips at once should account for the cars it's already sending.
9.6 Tiles for the whole planet tiles under 200 ms
- Vector tiles are small and styled on the device; one set serves light, dark and navigation styles.
- Pre-build zoom levels 0–14 for everywhere; build deeper zooms on first request and store them. The CDN absorbs nearly all reads.
- When map data changes (a new road), rebuild only the affected tiles and bump their version in the URL instead of purging caches.
9.7 The whole design after the deep dives
10. Interviewer follow-ups
Users want offline maps for a whole region.
Package the region's vector tiles, place index and routing graph (with its precomputed shortcuts, but static historical speeds) as a downloadable bundle, updated weekly. The phone routes locally; online, it still asks the server for traffic-aware routes. Bundles are versioned files on the CDN.
Add public transport.
A different problem: routes depend on timetables, so the graph is time-dependent. Algorithms built for timetables (scanning connections or rounds of trips) answer in milliseconds; live vehicle positions adjust departures. It's a separate service sharing places and tiles.
A new motorway opens tonight.
Map edits go through a validation pipeline into the next graph build. The affected cells are re-partitioned and re-customised, routing servers load the new version side by side and switch atomically, and the changed tiles get new versions. Rolling back means switching to the previous version.
One region's data centre goes down.
Routing servers for each region run in several zones and a second region holds a copy of the graph. Navigation continues on phones regardless; route requests fail over to the other region with slightly staler traffic.
How do you keep location data private?
Drop user IDs at ingestion; use rotating trip tokens; discard the first and last few hundred metres of each trace so homes aren't revealed; publish only segment speeds with enough samples; delete raw pings within hours.
ETAs are consistently 15% optimistic in one city.
That's model bias: compare predicted and actual times per city, road type and hour. Likely causes: a new road layout, events, or speeds from too few samples. Retrain with recent trips and add the city's error to the dashboard.
Traffic during a public holiday breaks the predictions.
Historical patterns assume a normal week. Treat holidays as their own time-of-week profiles, and lean more on live speeds when they diverge from history.
10× more users.
Tiles scale with the CDN. Routing scales with more replicas per region. Ping ingestion scales with partitions; aggregation is per segment, so it parallelises. The overlay graph stays small.
Show the three best routes, not one.
Find alternatives that are meaningfully different (share less than, say, 70% of their length) and not much slower, using penalties on the first route's segments and re-searching. Precomputed shortcuts keep each search cheap.
How would you test a routing change?
Replay a large set of real trips offline, compare route time and ETA error against the current version, then shadow-route a slice of live traffic before a gradual rollout.
11. When things break
| Failure | What users see | How we detect it | What limits the damage |
|---|---|---|---|
| Traffic pipeline stalls | Routes ignore new jams | Age of the newest segment speeds | Fall back to historical speeds; alert when data is over 5 minutes old |
| Bad graph build (missing road) | Strange detours | Offline replay comparison before rollout; route-length anomalies | Versioned graphs, staged rollout, instant rollback |
| Routing servers overloaded | Slow "Directions" | Route latency p99, queue depth | Autoscale replicas; shed alternative-route computation first |
| CDN or tile store issue | Blank map squares | Tile error rate by region | Second CDN; phones cache recently viewed tiles |
| Phone loses signal | Nothing, ideally | Stream disconnects | Route and tiles held locally; reconnect and resume |
| GPS noise in city canyons | Wrong-street jumps | Map-matching confidence | Hold the last good match; combine with heading and speed |
12. Wrap-up and the clock
Trade-offs we made:
- Heavy offline preprocessing for millisecond queries.
- A fixed partition with fast re-customisation, instead of rebuilding for every traffic change.
- Local navigation on the phone, with the server as an advisor.
- Aggregated, anonymised traffic instead of stored traces.
- Versioned tiles and graphs rather than in-place updates.
What we'd watch: route latency p99 · ETA error by region · traffic data age · tile error rate · reroute rate and acceptance · ping ingestion lag.
At 10×: more routing replicas per region; more stream partitions; tighter aggregation windows only where traffic is dense.
A 60-minute interview
| 0–5 | Frame: modes, world scale, live traffic, rerouting |
| 5–10 | Must do, how well, the graph and ping numbers |
| 10–15 | Nouns, contract, traffic data flow |
| 15–25 | First version: tiles, route, navigate; parked list |
| 25–50 | Deep dives: fast routing (9.1), live traffic (9.3), ETA (9.4) |
| 50–60 | Rerouting or tiles, follow-ups, wrap-up |
A 90-minute interview
| 0–8 | Frame, including privacy and poor connectivity |
| 8–15 | Must do, how well, numbers |
| 15–22 | Nouns, contract, data flow |
| 22–35 | First working version |
| 35–75 | Deep dives 9.1–9.6 and the final picture |
| 75–85 | Follow-ups: offline, transit, a bad graph build |
| 85–90 | Trade-offs, metrics, 10× |
| Level | What a strong answer shows |
|---|---|
| Mid-level | Tiles through a CDN, a graph search for routes, a location stream feeding traffic, a navigation session over a persistent connection. |
| Senior | Why Dijkstra is too slow with numbers, precomputed shortcuts or partitions, map matching and per-segment aggregation, ETA from historical plus live speeds, local navigation on the phone. |
| Staff+ | Fast re-customisation for live weights, privacy by design in the pipeline, versioned graph rollouts with offline replay, load-aware routing so recommendations don't create jams, ETA quality as a measured product metric. |
Common mistakes:
- Running Dijkstra over the world per request.
- Storing every ping in a database.
- Routing from live speeds alone for long trips.
- Making navigation depend on a live server connection.
- Rendering tiles on every request.
- Ignoring location privacy.
13. Try it, check yourself, read more
Route search lab. A small city as a grid of streets; every block takes one minute unless it's in the red jam. Pick a search and watch how much of the city it explores before finding the fastest route. Then switch the jam on and see the route bend around it.
A 30 × 17 grid (510 junctions). On a real continent Dijkstra would explore millions of junctions; precomputed shortcuts explore hundreds to a few thousand, which is why production routers use them.
What makes continental routing fast enough to answer in milliseconds?
Two million location pings arrive every second. What do you do with them?
For a two-hour trip, which speed should the ETA use for a road you'll reach in 90 minutes?
How does navigation keep working in a tunnel?
| Resource | Why |
|---|---|
| Customizable Route Planning (Delling, Goldberg, Pajor, Werneck, 2011) | Partitioned graphs with fast re-customisation for live traffic. |
| Contraction hierarchies | The shortcut idea in a readable overview. |
| Hidden Markov Map Matching Through Noise and Sparseness (Newson and Krumm, 2009) | The standard way to snap GPS points to roads. |
| Traffic prediction with advanced graph neural networks (Google DeepMind) | How ETA models use history and road structure. |
| OSRM and Valhalla | Open-source routing engines you can run on real map data. |
| Vector tile specification | What a vector tile contains. |