Engineering

Zero-Downtime Deploys That Actually Work

Rolling releases are the easy half. The hard half is database migrations, and that is where most 'zero-downtime' pipelines quietly fail.

Purushottam Kumar Suman
Purushottam Kumar Suman
Founder & CEO, Drema AI
9 min read
Engineer with a tablet working between server racks

Most teams achieve zero-downtime application deploys and then take an outage anyway, because a migration locked a table or removed a column the previous version still referenced. The application layer is the solved part; the schema is where the discipline is required.

01

Two versions run simultaneously. Always.

During any rolling deploy, old and new code serve traffic at the same time. Every change must therefore be compatible in both directions: the new code must work with the old schema, and the old code must survive the new one. Internalising this single constraint prevents most deployment incidents.

During a rolling deploy, both versions are live. Every change must be safe in both directions.

02

Expand, migrate, contract

Renaming a column in one step breaks the running version. Instead: add the new column, write to both, backfill, switch reads, stop writing the old, then drop it — across several releases. It feels laborious and it is the difference between a routine change and a 3am rollback.

ExpandAdd the new structure, nothing reads it yet
Dual writeBoth old and new populated
BackfillHistorical rows, in batches
ContractSwitch reads, then drop the old — a release later
03

Locks are the thing that bites

Adding a column with a default, adding a NOT NULL constraint, or creating an index can take an exclusive lock and stall every query behind it. In PostgreSQL, CREATE INDEX CONCURRENTLY and adding constraints as NOT VALID then validating separately avoid the worst of it. Test migrations against production-sized data, because a migration that takes 20ms on a dev database can take 20 minutes on the real one.

04

Backfill in batches, off the deploy path

Never backfill millions of rows inside a migration that blocks a deployment. Run it as a separate, resumable, rate-limited job that can be paused if it affects production load. Coupling data movement to deployment turns a slow backfill into an outage.

05

Health checks that mean something

A health endpoint returning 200 because the process started tells you nothing. It should verify the things that make an instance able to serve: database reachable, migrations at the expected version, critical dependencies responding. Otherwise the orchestrator routes traffic to instances that will fail every request.

06

Rehearse the rollback

A rollback path that has never been executed is a hypothesis. Practise it in staging until it is boring, and be explicit that forward-only is the correct choice for some schema changes — knowing which is which, before the incident, is the point of the exercise.

2 versions
Always live during a deploy
3 releases
For a safe column rename
Rehearsed
Rollback, not theoretical
Purushottam Kumar Suman
Written by
Purushottam Kumar Suman
Founder & CEO, Drema AI

Founder and CEO of Drema AI. Builds AI systems, SaaS platforms and industry software — and writes about what actually survives production.

CTA Background

Got a problem like this one?

Bring it to a call with a founder.You will get a straight answer, including when the answer is no.

View Our Work
AI-First Engineering
Secure & Scalable
Built to Deliver Impact