PostgreSQL Won So Completely, Nobody Writes the Postmortem for Leaving It

Cover Image for PostgreSQL Won So Completely, Nobody Writes the Postmortem for Leaving It

Every engineer I know has some version of the same story: the migration that started as a routine index rebuild and turned into a six-hour incident because the primary couldn't take a write lock without stalling every read replica behind it. Nobody tweets that story. Nobody writes it up. They fix it, add a runbook entry nobody outside the team will ever read, and move on. Multiply that by every company running Postgres past the point it was designed for, and you get an entire category of failure that the industry has almost no public language for — not because it's rare, but because admitting it happened means admitting you picked wrong, or grew faster than you planned, or both.

That silence is the actual story. PostgreSQL has topped Stack Overflow's "most admired database" ranking every year since 2021, and it's the default first choice for nearly every new backend built today — for good reason, it's free, it's mature, and its feature set (JSONB, full-text search, pgvector for embeddings) covers most of what a growing product needs without adding a second system. But "most admired" measures developer experience at the moment of adoption. It says nothing about what happens three years later, when a single-region, single-writer architecture hits a ceiling that no amount of admiration moves. The industry has a rich, detailed, well-cited vocabulary for choosing Postgres. It has almost none for the conversation that happens when a team needs to leave.

The Single-Writer Ceiling Nobody Budgets For

Postgres, like every mainstream relational database of its generation, has exactly one node that accepts writes. Everything else — read replicas, connection poolers, caching layers — is scaffolding built around that one fact. For most companies, for most of their life, this is not a problem; a single well-tuned primary on modern hardware handles a genuinely enormous amount of write throughput. But the failure mode when you do hit the ceiling isn't a gentle slowdown. It's WAL replication lag that turns a "read your own write" bug into an intermittent, unreproducible one. It's autovacuum falling behind on a hot table until a routine VACUUM becomes a multi-hour lock contention event. It's connection limits that force you into PgBouncer, which solves the connection problem and introduces its own transaction-pooling caveats that break prepared statements you didn't know you were using.

None of this shows up in a proof-of-concept. It shows up eighteen months after launch, usually during a growth spike, which is the worst possible time to discover it. And because the ceiling is a function of write volume and table size rather than a version number or a config flag, there's no clean signal that tells a team "you are now the kind of company that needs to think about this." Teams find out by hitting it.

Why the Teams That Leave Don't Write About It

Notion published one of the only detailed, honest public accounts of this transition in 2021, describing how they sharded their Postgres fleet after outgrowing a single-primary setup under rapidly growing workspace data. It's still, years later, one of the most-cited posts on the topic — not because it's uniquely well-written, but because almost nobody else has published its equivalent. That scarcity is the tell. Engineering teams write detailed retrospectives about picking a new framework, adopting a new deploy pipeline, even about outages caused by someone else's cloud provider. They go quiet exactly at the moment their own database architecture stopped working, because that failure implicates a decision someone on the team made and defended, possibly the same someone writing the postmortem.

Compare that to how freely companies publish "why we chose Postgres" posts. That genre is enormous, low-risk, and flattering — it reads as a smart, boring, defensible decision. "Why we spent four months migrating off Postgres because our write volume outgrew a single primary" is a much harder post to publish, because the honest version of that story includes "we didn't see this coming," which is a worse look than "we made a mistake and fixed it fast."

The Vocabulary Gap That Follows From the Silence

Because so few teams document the exit, the industry has never converged on a shared way to talk about when to leave. Ask ten senior engineers when a team should consider Citus, Vitess, CockroachDB, or YugabyteDB over vanilla Postgres, and you'll get ten different heuristics, most improvised on the spot, because there's no canonical playbook to reference — unlike, say, the well-worn advice on when to introduce a cache or a queue. Each of these distributed options solves the single-writer problem differently, and each comes with a real cost that the marketing pages undersell: Citus keeps you in the Postgres ecosystem but requires you to design your schema around a shard key from day one, which is nearly impossible to retrofit gracefully. CockroachDB and YugabyteDB give you horizontal writes natively but change your consistency and latency model in ways that surface as new, unfamiliar bugs — cross-shard transactions that used to be a single ACID commit are now a distributed one, with all the partial-failure modes that implies.

A team facing this decision today is mostly reasoning from first principles, because the people who've already made this call took the lessons in-house and left the internet with a knowledge gap where the case studies should be.

So Actually — the Problem Was Never the Database

The instinct is to treat this as a technology story: Postgres versus its distributed alternatives, tradeoffs on a feature matrix. That's the wrong frame. The real problem is organizational, not technical — there's no normalized moment where a team is expected to ask "are we still the kind of company Postgres was designed for?" the way there's a normalized moment to ask "should we introduce a cache?" Because that question has no socially safe entry point, teams don't ask it proactively. They ask it retroactively, mid-incident, under the worst conditions to make an architecture decision, which is exactly backwards from how the decision should get made.

The fix isn't a new database. It's treating "when do we outgrow our current data architecture" as a scheduled, unglamorous check — the same way teams schedule a security audit nobody's excited about — instead of waiting for the ceiling to announce itself at 3 a.m. Postgres earned its dominance. What it didn't earn was an industry mature enough to talk honestly about the day it stops being the right answer.

If you're running Postgres at scale and thinking about what comes after connection pooling stops being the fix, the indexing work and pgvector production patterns worth doing first are the ones that buy you the most runway before you need to have this conversation at all.

The next team to hit this wall will do exactly what the last one did: patch it, ship the fix, and never write it down. The pattern doesn't break until someone treats the exit as normal enough to talk about before they're forced to.