Collapsing Ecto Migrations
A migration file that no longer provides value as a distinct migration is just dead weight. It’s a liability. When an application reaches a year or two in age, the list of database migrations in its history can grow to an impressive size. Sometimes, changes to an application will cause migrations from the past to fail. When a new developer onboards the application, they can get blocked by these bugs.
What if there was a way to flatten all old migrations into a single database schema? There is.
Here’s how to do it:
- Pick the most recent migration that is deployed to production. Delete all the migrations before it.
- Get a schema dump of the production database, with no data. Just the schema. Save it to
/priv/repo/initial_schema.sql
. For PostgreSQL, that might look something like this:pg_dump my_database --schema-only --no-owner --exclude-table=schema_migrations > schema.sql
- Rename the latest migration file and module name. Keep the timestamp in the filename, but rename the rest to something like “_initial_schema.exs”. Similarly, rename the module.
- Replace the body of the module with the module body shown above.
- Remove all migration files that came prior to this migration.
- Test it in the
test
environment:MIX_ENV=test mix do ecto.drop, ecto.create, ecto.migrate
. Thenmix test
.
The modified migration calls out to psql
, and passes the same connection parameters that the application’s Repo
module uses. The schema dump is imported into the database via psql
. This works for PostgreSQL. If you’re using another database, replace the psql
command with the command that is provided by your database.