HomeResourcesCase study
Case study

Why Uber Left the Database Everyone Recommends

By The SDL team·3 min read·Updated Sep 16, 2026

Postgres vs. MySQL isn't a religious war. It's a question you can't answer until you name your write pattern.

Uber moved off Postgres — the database the internet loves to recommend — and onto MySQL. The reason wasn't that one is "better." It's that Uber's write pattern made Postgres pay a tax most apps never notice.

This is the post that launched a thousand arguments. Strip away the tribalism and it's a clean lesson in how a database's internal design meets your specific workload — and why "best database" is a question with no answer until you name the workload.

Plain English

When you change one field in a row, you'd hope the database changes just that field. Postgres, to support its versioning and concurrency model, often writes an entirely new copy of the row — and then has to update every index on that table to point at the new copy, even indexes on fields you didn't touch. That multiplication of physical writes per logical change is write amplification.

For a read-heavy app, who cares. For Uber — constantly updating trip state, locations, driver status — that tax landed on the hottest path, and it compounded across replication to every replica.

Now the engineering

The root cause is how each engine links indexes to data. In Postgres, every index entry points to a row's physical on-disk location (its ctid). Update a row, it moves, and all indexes must be rewritten to chase it. InnoDB (MySQL) takes a different tack: secondary indexes point to the primary key, not a physical location. The row can be updated in place, and secondary indexes — addressed logically by PK — don't all need rewriting on every change.

Write amplification: one logical update, many physical writes Postgres: row has a physical location index → ctid (on-disk row) UPDATE one field new row version written → EVERY index must be updated to point to it + replication ships all of it MySQL/InnoDB: index points to primary key secondary index → PK UPDATE one field row updated in place secondary indexes by PK don’t all need rewriting replication ships logical rows Same workload, very different write cost. The data model dictated the database — and Uber’s workload made Postgres’s versioning model expensive.
Two index models, two write costs. Uber's update-heavy workload turned Postgres's physical-location indexing into expensive write amplification; InnoDB's PK-based indexing fit better.

Uber also hit pain with Postgres's replication (shipping the heavy physical changes) and its connection model (a process per connection, costly at high concurrency). MySQL's logical replication and connection handling suited their scale and write mix. Most databases ended up behind Uber's Schemaless layer; some legacy Postgres and Cassandra stayed for specialized cases.

Worth knowing

Read this post as a case study, not a verdict. Postgres's design is excellent for countless workloads; Uber's quarrel was with a specific interaction between its update-heavy pattern and Postgres's MVCC + indexing. The transferable skill is reasoning about that interaction — not memorising "Uber picked MySQL."

The gap it reveals

"SQL vs NoSQL" and "Postgres vs MySQL" are framed as religious wars. The senior realisation is that the right answer depends on a measurable property of your workload — here, write amplification under a heavy-update pattern — and that you must understand the engine's internals (how indexes reference rows) to predict it. That's reasoning from mechanism, not from tribe.

In the interview room

When you pick a datastore in a design round, expect: "why that one?" A weak answer lists features. A strong one ties the engine's internals to your access pattern: "this is update-heavy with many secondary indexes, so I care about write amplification — which makes InnoDB's PK-based indexing attractive." That sentence shows you reason about databases the way their authors do.

The reframe

There is no best database. There's only the best database for a workload, and you can't evaluate the fit until you can describe the workload in terms the engine cares about — read/write ratio, update locality, index count, concurrency. Uber's move looks controversial only if you skipped the step where they named their workload.

Stop asking which database is better. Start describing what you'll actually do to it.

Primary source →
uber.com — Why Uber Engineering Switched from Postgres to MySQL

Want feedback on your design?

The weekly teardown

One real-world architecture, every week.

How real companies actually built it: the design, the trade-offs, and what to say about it in an interview. Free, and one click to unsubscribe.

Related articles