Engineering

Zero-Downtime Database Migrations: A Practical Guide

August 12, 2025

Taking the app down for a schema change isn’t an option when you have millions of daily users. We use expand-contract (parallel change) migrations: add the new column or table first, backfill in the background, switch reads/writes, then remove the old path.

For large tables, we rely on online DDL where the database supports it (e.g. pt-online-schema-change for MySQL, or native ALTER with minimal locking). Batching and chunking prevent long-running transactions and replication lag.

Blue-green or canary deployments at the application layer let you roll out code that understands both old and new schema before flipping. Feature flags can gate the new code path until backfill completes.

The golden rule: never deploy a migration and code in the same release. Deploy the migration first, then the code that uses it—or the reverse with backward-compatible code first, then migration to drop the old schema.