Why Migration Strategy Matters
Schema changes are the riskiest part of deployments. A bad migration can lock tables, corrupt data, or cause downtime. With proper strategies, you can evolve your database schema safely — even under heavy traffic. The key principle: make all changes backward-compatible.
Expand-and-Contract Pattern
The gold standard for zero-downtime migrations. Expand: add the new column/table alongside the old one. Deploy code that writes to both. Migrate: backfill existing data to the new structure. Contract: remove the old column/table after all code uses the new one. This requires at least three deployments but guarantees zero downtime.
Dangerous Operations to Avoid
Never in a single step: rename a column (add new → migrate → drop old), change a column type (add new column → cast data → swap), add a NOT NULL constraint without a default (add with default first → then make NOT NULL), or drop a table still referenced by running code. Each requires the expand-and-contract approach.
Migration Tools
Flyway: SQL-based, version-numbered migrations. Simple and reliable. Prisma Migrate: TypeScript-first, generates SQL from schema changes. Alembic: Python/SQLAlchemy, auto-generates diffs. golang-migrate: Lightweight Go tool. All track applied migrations in a metadata table and support up/down operations.
Testing Migrations
Always test against production-sized data. A migration that takes 1ms on 100 rows might lock a table for 30 minutes on 10 million rows. Use pt-online-schema-change (MySQL) or pg_repack (PostgreSQL) for large table alterations. Run migrations in staging with production data snapshots before deploying to production.
Rollback Strategies
Write explicit down migrations for every up migration. For data-destructive changes, take snapshots before migrating. Consider forward-fix over rollback — sometimes it's faster to fix the issue and push a new migration than to reverse a complex change. Document rollback procedures for every migration.
Conclusion
Database migrations don't have to be scary. Use expand-and-contract for structural changes, test with production-like data, and always have a rollback plan. The extra discipline pays off — zero-downtime deployments become routine instead of stressful events.