Database Engineering

MySQL Schema Migration Best Practices: Expand-Contract and Batch Backfills

Execute MySQL schema migrations safely with the expand-contract pattern, batched backfills, backward-compatible changes, and migration tooling comparison (Flyway, Liquibase, gh-ost).

JusDB Team
Published September 3, 2025
5 min read

Database schema migrations are one of the riskiest operations in production deployments. A failed or slow migration can cause outages lasting hours. Here are the patterns that make migrations safe and reversible.

Expand-Contract Pattern

The safest way to rename a column or change a type without downtime:

text
Phase 1 (Expand): Add new column, write to both old and new
Phase 2 (Migrate): Backfill new column from old column
Phase 3 (Contract): Deploy code reading only new column, drop old column
sql
-- Phase 1: Add new column
ALTER TABLE users ADD COLUMN full_name VARCHAR(255);

-- App writes to both 'name' and 'full_name'

-- Phase 2: Backfill
UPDATE users SET full_name = name WHERE full_name IS NULL LIMIT 1000;
-- Repeat in batches until complete

-- Phase 3: Drop old column (after code no longer reads it)
ALTER TABLE users DROP COLUMN name;

Backward-Compatible Migrations Only

  • Never add a NOT NULL column without a DEFAULT in the same deploy
  • Never rename columns — add new, migrate, drop old
  • Never remove columns until all code references are gone
  • Never change column types in place — use expand-contract

Batch Large Data Migrations

sql
-- Backfill in small batches to avoid long-running transactions
SET @batch_size = 1000;
SET @last_id = 0;

REPEAT
  UPDATE users
  SET new_col = derive_value(old_col)
  WHERE id > @last_id AND new_col IS NULL
  ORDER BY id
  LIMIT 1000;

  SELECT MAX(id) INTO @last_id
  FROM users WHERE new_col IS NOT NULL;

  DO SLEEP(0.05);
UNTIL ROW_COUNT() = 0 END REPEAT;

Migration Tooling

  • Flyway: Java-based, SQL-first, good for teams with DBAs
  • Liquibase: XML/YAML/SQL, supports rollback scripts
  • gh-ost / pt-osc: for ALTER TABLE on large tables
  • Sqitch: Git-based change management with deploy/revert/verify

Always Test Rollback

bash
# Flyway rollback
flyway undo

# Liquibase rollback
liquibase rollbackCount 1

# Test your rollback in staging before running migration in production

Key Takeaways

  • Use expand-contract for column renames and type changes — never in-place
  • Always backfill in small batches with SLEEP between iterations to avoid replication lag
  • Write rollback scripts before you run migrations — you will need them eventually
  • Test migrations in a production-clone environment with production-size data

JusDB Can Help

Schema migration failures are a leading cause of production incidents. JusDB can review your migration strategy and help you implement a safe deployment process.

Share this article

Database engineering notes

Articles like this one, in your inbox. No spam, unsubscribe anytime.

JusDB Team

Official JusDB content team

Keep reading

Open Source Databases (2026): PostgreSQL, MySQL, ClickHouse, Cassandra & Beyond

Navigate the open source database landscape. Compare MySQL, PostgreSQL, MongoDB, Redis, and Cassandra with detailed feature analysis and selection criteria.

PostgreSQL5 minMay 13, 2026
Read

Liquibase vs Flyway: Which Database Migration Tool to Choose?

Compare Liquibase and Flyway for schema migration management — features, abstraction level, and team fit

11 minJan 31, 2026
Read

Apache Airflow for Database Workflows: Scheduling and Orchestration

Use Apache Airflow to orchestrate database ETL, backup jobs, and maintenance tasks — DAGs, sensors, and best practices

12 minJan 30, 2026
Read