Detect Migrations Drift in CI
How to detect schema drift in CI and ensure the migration directory is up to date with the desired schema state - ORM, HCL, SQL, or any other schema definition?
How to detect schema drift in CI and ensure the migration directory is up to date with the desired schema state - ORM, HCL, SQL, or any other schema definition?
With Atlas, we advocate for treating migration directories as deployment artifacts resulting from a structured build process. The preferred approach is to push migration directories to the Atlas Schema Registry. In addition to its role as a migration directory storage, the Schema Registry provides a tight integration with the Atlas CLI and the Atlas Cloud UI, allowing you to deploy migrations, visualize schemas over time, review deployment logs and errors, and more.
However, some users prefer to store their migration directories in S3, typically due to internal policies or requirements.
PostGIS is a spatial database extension for PostgreSQL. It adds support for geometric objects, enabling the processing
of spatial data like points, lines, and polygons. After installing PostGIS, the GEOMETRY
data type can be used to define
tables that capture geo-spatial data, for example:
Developers who use Atlas to run migrations using a golang-migrate
directory format, may run into an errors like:
-- migrating version 20250324061649.down.sql
-> DROP TABLE `users`;
Error 1051 (42S02): Unknown table 'public.users'
Why does atlas migrate diff
fail with the following error after running atlas migrate apply
?
Error: sql/migrate: connected database is not clean: found table "atlas_schema_revisions" in schema <schema_name>. baseline version or allow-dirty is required
How to generate an SQL schema file from an existing migrations directory to quickly set up a database for integration tests?
When working with multiple branches and applying hotfixes directly to production, out-of-order migration conflicts may occur if migration files are created with timestamps that don't reflect the actual merge order.
Consider this scenario:
Initial state:
001_initial.sql
001_initial.sql
002_add_posts.sql
004_add_index.sql
After hotfix applied directly to production:
001_initial.sql
003_hotfix_add_email.sql
← hotfix added001_initial.sql
002_add_posts.sql
004_add_index.sql
After merging master into dev - the problem:
001_initial.sql
- Applied to production002_add_posts.sql
- Dev-only, not applied to production003_hotfix_add_email.sql
- Applied to production004_add_index.sql
- Dev-only, not applied to productionThis creates a non-linear migration history where migration files 002
and 004
were created before and after the hotfix timestamp but haven't been applied to production.
Incorporate the latest changes from master into your dev branch:
git checkout dev
git merge master # or git rebase master
This will create a conflict in the atlas.sum
file, which is expected. Resolve the git conflicts as usual, choosing any version number for atlas.sum
.
The version number doesn't matter because you will then re-hash the migration directory by running:
atlas migrate hash
Since the hotfix was applied to production but not to your dev database, you must bring your dev database to a consistent state before rebasing migrations.
# Apply only the missing hotfix migration
atlas migrate apply --url "mysql://root:pass@localhost:3306/development" \
--exec-order non-linear
The --exec-order non-linear
flag in Atlas lets you run migration files even if they weren’t created in order. This is handy when multiple developers add migrations at the same time and version numbers don’t line up. Learn more about execution order options.
With your dev database in a consistent state, run atlas migrate rebase <versions>
to shift pending migrations to come after the hotfix. Rebase only the files that haven't been applied to production:
# Rebase the dev-only migrations
atlas migrate rebase 002 004
This command will:
atlas.sum
file with the new checksumsAfter rebasing, your migration directory should look like:
migrations/
├── 001_initial.sql
├── 003_hotfix_add_email.sql # hotfix from master
├── 005_add_posts.sql # rebased (was 002_add_posts.sql)
├── 006_add_index.sql # rebased (was 004_add_index.sql)
└── atlas.sum
Since your development database already has the schema changes from the rebased migrations applied, mark them as applied to avoid re-execution:
atlas migrate set 006 --url "mysql://root:pass@localhost:3306/development"
Using atlas migrate set
will update the atlas_schema_revisions
table to mark migrations as applied without actually executing them. This can cause inconsistencies in the revision history.
Update the PR and deploy the changes:
atlas migrate apply --url "mysql://root:pass@aws-rds:3306/production"
Working with a local development database? Here's a shortcut that can save you some steps! Instead of the careful sync process in Steps 2 and 4, you can just reset your database after rebasing.
Skip Steps 2 and 4 entirely. Just do Step 3: Rebase migrations first, then:
# Clean the dev database and reapply all rebased migrations
atlas schema clean --url "mysql://root:pass@localhost:3306/local"
atlas migrate apply --url "mysql://root:pass@localhost:3306/local"
This method keeps your migration history of the local development database consistent with the production database.