Blog/SaaS & Startups

Zero-Downtime Database Migrations: A Safe Process for SaaS Teams

Use expand-and-contract migrations, review rules and rehearsals so schema changes stop causing outages or data loss in production.

By Sagar Makker · 7 min read · October 2026
Coding Programming
In short
Split risky schema changes into expand, migrate and contract steps across releases.
Review every migration for locks, data volume and rollback before it ships.
Rehearse large migrations on a production-sized copy and backfill in batches.
The problem

This is for CTOs and backend leads at SaaS companies where a schema change has already caused an outage, or soon will. As tables grow, a migration that ran instantly in development can lock production for minutes or corrupt data mid-way. This post gives you the expand-and-contract pattern, a migration review checklist, a batch backfill approach and a rehearsal routine, so your database can change as fast as your product without taking customers down.

An engineer adds a column with a default value to the orders table and renames another in the same migration. It runs in seconds on staging. In production, with years of orders, the table locks, checkout requests queue up and time out, and the app servers still running the previous release start failing because the old column name has disappeared.

Database changes are often reviewed as ordinary code even though they behave very differently. They run once, against real data, and cannot simply be redeployed if wrong. Teams combine destructive and additive changes in one step, test on small datasets and lack a rollback plan. Each scare makes engineers avoid needed schema improvements, which builds data model debt over time.

Why it happens
01Additive and destructive changes are combined into a single migration
02Migrations are tested only on small development or staging data
03Locking behaviour of the database engine is not checked for large tables
04Backfills run as one huge update instead of controlled batches
05No rollback plan or backup verification before risky migrations
How to fix it
1
Adopt expand and contract
The backend lead makes it a rule: first add new columns or tables, then deploy code writing to both, backfill, switch reads, and only later remove the old structure in a separate release.
2
Create a migration review checklist
A designated database reviewer checks each migration for table size, locks taken, index creation method, defaults on large tables, reversibility and compatibility with the currently running application version.
3
Backfill in small batches
Engineers run data backfills as background jobs in batches with pauses, progress logging and the ability to stop and resume. The backend lead sets batch size based on observed database load.
4
Rehearse on production-sized data
For migrations touching large tables, the engineer runs them on a recent masked copy of production first, timing each step. The database reviewer signs off only after seeing realistic run times.
5
Confirm backups and rollback path
Before risky migrations, the on-call engineer confirms a recent restorable backup and writes the rollback steps. Schedule them in a low-traffic window, with someone watching database metrics throughout.
Worked example
A school management SaaS splits a risky change

A school management SaaS in Chennai needed to restructure how fee records linked to students, on one of its largest tables. A previous schema change had locked the database during admission season. This time the backend lead used expand and contract: a new table was added, code wrote to both structures, and a batched background job backfilled history over several nights. Reads switched once counts matched, and the old columns were dropped weeks later. The migration was rehearsed on a masked production copy first. Customers saw no downtime, and engineers became more willing to fix awkward parts of the schema.

Common mistakes
×
Renaming columns in a single step
Running application servers still use the old name and fail instantly. Add the new column, write to both, migrate reads, then drop the old one later.
×
Running migrations automatically on every deploy
Large or locking migrations can run at a bad time without anyone watching. Run risky migrations as a separate, supervised step with a named owner.
×
Testing on unrealistic small datasets
Timing and locking only show up at production scale. Rehearse heavy migrations on a recent masked copy and check data protection rules for that copy.
Where an AI agent helps
Input
Migration files, table sizes, index definitions and current schema
Agent does
An agent on XDQ AgentOS checks migrations against the review checklist and flags lock or compatibility risks
Human gate
Database reviewer approves each flagged migration before it is merged or run
Outcome
Migration risk notes, suggested split steps and a rollback outline
Checklist
Make expand and contract the default for schema changes
Name a database reviewer for every migration
Check locks and table size before approving
Run backfills as batched, resumable background jobs
Rehearse large migrations on a masked production copy
Verify a restorable backup before risky changes
What to measure
Incidents caused by migrations
Migrations rehearsed before production
Longest table lock during a release
Open contract steps awaiting cleanup
Questions
What is the expand and contract pattern?

It splits a breaking schema change into safe stages: add the new structure, write to both old and new, backfill, switch reads, then remove the old structure later. Each step is backward compatible, so running code never breaks.

Should migrations run automatically during deploys?

Small additive migrations can run automatically. Large backfills, index builds on big tables and destructive changes should be run as separate, supervised steps with an owner watching database health and ready to stop them.

Can we use production data to rehearse migrations?

Use a recent copy with personal and sensitive data masked, and restrict access to it. Check your obligations under data protection rules, including the DPDP Act, with your compliance team before creating such copies.

How do we roll back a migration that has gone wrong?

With expand and contract, you usually roll back the application rather than the schema, because the old structure still exists. For destructive steps, rely on a verified backup and written restore steps prepared before running the migration.

Keep reading
All posts →
Team MeetingSaaS & Startups
API Versioning Strategy for SaaS: Change Without Breaking Customers
7 min readRead →
Coding ProgrammingSaaS & Startups
SaaS Data Model Design: Early Decisions That Save Painful Rewrites
7 min readRead →
Code CodingSaaS & Startups
A SaaS Release Process Small Engineering Teams Can Run Every Week
6 min readRead →
Next step

Want this fixed in your business?

Send the workflow. You get a scope and a fixed price within two working days — or a straight answer that it isn't a fit.

Secure by default · find → fix → verify · authorised scope only
Send a brief →enquiry@xdqlabs.com