Migration
my-GRAY-shun
A scripted, versioned change to a database schema that evolves the data structure over time.
A migration is a versioned script that changes the database schema. Add a column, create a table, modify an index: each change is a migration file with a timestamp and a description. Migrations run in order, transforming the database from one state to the next.
Migrations solve the problem of keeping the database in sync across environments. When a developer adds a migration, every other developer's database updates when they pull the code and run migrations. Staging and production update when they deploy. Everyone stays on the same schema version.
Reversible migrations include both an "up" (apply the change) and a "down" (undo the change). Not all migrations are safely reversible. Dropping a column is not reversible because the data is gone. Data-only migrations (backfilling a new column) are harder to reverse. The "down" migration is a safety net, not a guarantee.
Examples
A developer adds a new feature that needs a column.
The feature requires a 'last_login_at' timestamp on the users table. The developer creates a migration file: ALTER TABLE users ADD COLUMN last_login_at TIMESTAMP. They run it locally, commit it with their code, and it runs in staging and production during deployment.
A migration fails in production.
A migration adds a NOT NULL column without a default value. It works on an empty staging database but fails in production because existing rows have no value for the new column. The fix: add the column as nullable first, backfill existing rows, then add the NOT NULL constraint.
A team runs a data migration.
The team splits the 'name' column into 'first_name' and 'last_name'. The migration adds two new columns, parses existing names to populate them, and then drops the original column. They test with a copy of production data first to verify the parsing handles edge cases.
In practice
Read more on the blog
Frequently asked questions
What tools are used for database migrations?
Most frameworks include migration tools: Rails has ActiveRecord migrations, Django has its migration framework, and Node.js teams use Prisma, Knex, or TypeORM. Standalone tools like Flyway and Liquibase work with any language. Choose the tool that integrates with your ORM or framework.
How do you handle migrations with zero downtime?
Use a multi-step process. To add a NOT NULL column: first add it as nullable, deploy code that writes to it, backfill existing rows, then add the constraint. To rename a column: add the new column, copy data, deploy code that reads from the new column, then drop the old one.
Related terms

Want the complete playbook?
Picks and Shovels is the definitive guide to developer marketing. Amazon #1 bestseller with practical strategies from 30 years of marketing to developers.