Migrations

Zero-Downtime PostgreSQL Migrations: A Practical Playbook

“Just take a maintenance window” isn’t an acceptable answer anymore. Here’s the logical-replication pattern we use to cut production PostgreSQL clusters over without customers noticing.

June 18, 2026 · 8 min read · AG Data Team

A maintenance window used to be the default answer to "how do we migrate the database." For a lot of production systems today, it isn't an option anymore — logistics platforms, payment systems, and gaming backends don't have a quiet 2 a.m. window where nobody notices a few hours of downtime. The traffic doesn't stop, and neither can the database.

The good news is that PostgreSQL has supported logical replication natively since version 10, and the pattern for using it to run a zero-downtime migration is well understood. The bad news is that most of the risk in a migration like this isn't in the replication technology — it's in the dozen small details around it that don't get replicated automatically.

The core technique

Logical replication streams row-level changes from a source database to a target, independent of the underlying infrastructure on either side. That's what makes it useful for migrations that cross cloud providers, major version upgrades, or moves between wildly different environments — the source keeps taking production traffic while the target quietly stays in sync in the background.

The migration itself follows a predictable shape:

  1. Baseline and inventory. Schema, extensions, sequences, triggers, foreign data wrappers, and anything else that logical replication doesn't carry over on its own.
  2. Stand up the target and replicate the schema — not just tables, but indexes, constraints, and extension versions that match the source closely enough to behave the same way under load.
  3. Initial bulk copy of existing data, followed by a replication slot that starts catching up on everything written since the copy began.
  4. Validate under real traffic. Row counts and checksums first, then replication lag under actual production load — not a synthetic benchmark.
  5. Cut over. A short, measured window — seconds, not hours — where connections drain from the old target and reconnect to the new one.
  6. Hold the rollback path live for days after cutover, not minutes. The old cluster keeps receiving replicated changes in reverse until the new one has proven itself under a full business cycle.

We've run this exact pattern on clusters sustaining more than 16,000 transactions per second during the cutover window itself — the technique holds up as well at that scale as it does on a modest single-region deployment. The difference at scale is entirely in how much validation happens before anyone touches the cutover switch.

Where migrations actually go wrong

Almost none of the incidents we've seen in PostgreSQL migrations were caused by logical replication failing to replicate. They were caused by things logical replication was never going to handle in the first place:

What actually makes it zero-downtime

The replication technology gets you 90% of the way there. The other 10% — sequence resync, DDL discipline, connection draining, and a rollback plan you're actually willing to use — is where the engineering effort goes, and it's the part that's easy to underestimate if you've only read about logical replication rather than run a cutover on a live production system.

Key takeaways

PostgreSQL Migrations High Availability Logical Replication
Work with us

Planning a migration you can't afford to get wrong?

We've run this pattern across clusters processing tens of thousands of transactions per second. Let's talk through your specific constraints before you touch anything in production.

Get in touch More from the blog