Uber Eats search had gotten so slow that Uber's own engineers called it untenable. Then they cut the wait in half. The surprising part: no single change saved more than about 200 milliseconds. Some saved twenty.
In September 2026, Uber Engineering published every change behind it. This post follows one search through the whole pipeline and pulls out the five ideas behind the fixes, ideas that work on any system you build. The animated version:
Eight p.m., sushi: the six stages of a search
Here's the search we'll follow. It's 8 p.m. Maya opens Uber Eats and types sushi.
- Query understanding works out what she means: sushi is a dish, not the name of a restaurant.
- Retrieval searches a catalog of a few billion items for every restaurant and roll that could match.
- Hydration fetches the facts about each candidate: the signals a ranking model needs to judge it.
- Ranking scores the candidates so the best few rise to the top.
- Presentation turns the winners into cards, with prices and photos.
- Finally, the cards travel back to Maya's phone and draw on screen.
Six stages, one after another, and Maya waits through all of them.
Idea 1: measure what the user sees
The usual answer to "how slow is it?" is back-end response time: how long the server takes to reply. Uber changed the clock. Their metric is above the fold: from the moment Maya taps search to the moment the first screen of results is fully drawn, images included.
That clock counts things the server timer never saw: sending results over the network, building the cards, loading the photos. And it pointed straight at the first fix. The server was building every result, one card at a time, before sending any of them.
Now it sends a small first page and keeps the rest cached on the server for when Maya scrolls, and the cards render at the same time instead of one by one. Together, those two changes made the first screen appear more than 200 ms sooner, the biggest single win.
Idea 2: delete work before you speed it up
Retrieval was running several search strategies side by side and merging what they found. Some matched by meaning, some matched plain words. Uber checked what each one actually added. Several broad word-matching strategies were slow and contributed little the others hadn't already found. Removing them saved about 120 ms, by deleting code. Duplicate chain stores are now removed earlier too, so every later stage carries fewer candidates.
The catalog itself got the same treatment. Many of its few billion items are the same product sold by different stores, and every listing used to be its own item with its own data to fetch. Grouped by the product underneath, the catalog is roughly 100 times smaller, and fetching data once per product cut lookups by more than 100 times, about 50 ms.
Idea 3: don't wait on what you don't need
Hydration used to be one big step: fetch everything about every candidate, then rank. But ranking only needs the signals its model scores. The price of Maya's salmon roll, the promotion, whether it's in stock: those only matter when the card is drawn.
So Uber split hydration in two. Ranking hydration fetches only what scoring needs; presentation hydration fetches the display details at the same time, in parallel. Ranking no longer waits for prices it never reads, which was worth more than 100 ms. Removing false dependencies between steps, where one step waited on another it didn't actually need, saved about 35 ms more.
Idea 4: hedge the tail
Hydration also fans out: one search asks many machines at once, each holding one slice of the data, called a shard. The answer is only as fast as the slowest shard. Most shards answer quickly, but now and then one stalls for a moment, and with enough shards per search, one of them is often stalling. That's tail latency: a rare slow case, multiplied by fan-out, becomes the common case.
Uber's fix is request hedging. If a shard hasn't answered within a time limit, send the same request to another copy and take whichever answer comes back first. It works because the stalls were isolated, one shard at a time, and it saved 40 ms.
It's safe here because hydration only reads. Send a payment twice and you charge twice: writes need idempotency keys.
Idea 5: lay data out the way it's read
Every search runs a small ad auction with hundreds of bids to score. The bids were stored row by row, with the same shared details repeated in every row. But scoring reads one field across every bid, like running down one column of a spreadsheet, so Uber stored the bids as columns and moved campaign and pacing data into the ad service's own memory. Ad selection got about 30 ms faster, bid preparation about 110 ms, and cutting needless format conversions saved 20 ms more.
The plumbing had the same lessons:
- Results encoded one after another left most CPU cores idle; encoding in parallel saved more than 50 ms.
- Embeddings rounded to five decimal places and packed compactly shrank 46%, and their database queries got twice as fast.
- The service mesh capped requests per connection, so busy services queued silently; parallel connections removed up to 53 ms.
- In some Go services, garbage collection was eating more than 40% of the CPU. Plain values instead of pointers let data live on the stack and disappear when a function returns.
Uber even built an AI agent loop that profiles live latency, drafts fixes, opens pull requests and benchmarks them. In Uber's words, what it finds is "individually uninspiring but compound meaningfully at scale."
Takeaways
- Measure what the user sees, not what your server times.
- Delete work before you make it faster.
- Draw your request's dependency graph; anything that doesn't need to wait, shouldn't.
- Hedge the tail on reads; never on payments.
- Lay data out the way it's read, and keep the hot part in memory.
None of those fixes was big on its own. Together, Maya's sushi shows up in half the time.
Watch the full animated breakdown: https://youtu.be/QlzyLS6ll24
Sources: Uber Engineering, "Halving the Time: How Uber Eats Rebuilt Its Search Pipeline" (Sept 2026), https://www.uber.com/us/en/blog/uber-eats-search-pipeline/ ยท InfoQ, https://www.infoq.com/news/2026/10/uber-eats-search-latency/
Practice designing systems like this yourself at https://systemdesignlab.in






Top comments (0)