Real atlas migrate apply, against production's shape
Connect a repository and DbProof finds the folder with atlas.sum and opens a pull request with the workflow.
Restore production's shape
The check starts a throwaway Postgres on production's major version in your runner and restores the latest snapshot of production's schema and atlas_schema_revisions.
Apply one version at a time
Atlas runs with --to-version for each new migration in turn, so a finding names the file that caused it.
Weigh it against production
DbProof compares the result with production's statistics and reports on the pull request as a check and a comment, with the file, the line and a suggested fix.
The setup pull request installs Atlas and points it at the check's database:
- uses: ariga/setup-atlas@v0 - uses: dbproof/check-action@v1 with: project: your-org/ledger migrations-dir: migrations migrate-command: atlas migrate apply --dir "file://migrations" --url "$DBPROOF_CHECK_DSN"
What the check reports
Each finding names the migration file and line, says what production would do, and suggests a fix. Errors fail the check; warnings don’t.
NOT NULL on a column with nulls
Production's statistics show nulls, so SET NOT NULL fails mid-deploy.
Migration fails to apply
A hotfix already added the column in production. The migration replays cleanly on the dev database and fails on deploy.
Index built without CONCURRENTLY
Writes to a large table blocked while the index builds. The fix builds it concurrently, in a file Atlas runs outside a transaction (-- atlas:txmode none).
Table rewrite on a table over 1M rows
A type change that rewrites the whole table while holding its lock.
Foreign key without an index
Every delete from the parent scans the child table.
Dropped column
Code still reading it breaks the moment the migration runs.
A stale atlas.sum
Atlas refuses to run a folder whose sum doesn't match its files. The check says so, and to run atlas migrate hash.
Production changed outside migrations
DbProof opens a pull request with a migration that adopts the change and an updated atlas.sum.
Structure and statistics, never rows
A capture step in your deploy job reads production with the connection string your migrations already use, and uploads a snapshot.
What capture reads
- The catalog: tables, columns, indexes, constraints, views and functions
- Planner estimates: row counts, and each column's share of nulls, distinct values and width
atlas_schema_revisions, in Atlas's own schema or, as on Neon, inpublic
What it never reads
- Rows from any of your tables
- Sample values: no most-common values, no histograms
- Your connection string: it stays in your GitHub secrets
Atlas questions
Declarative mode, atlas schema apply?
Not yet. DbProof tests versioned migrations: the files in your migrations folder, applied with atlas migrate apply.
How is this different from atlas migrate lint?
Lint analyzes your migrations on a dev database. DbProof applies them to a copy of production's schema and weighs them against production's statistics, so it knows that a column already has nulls, that a table has 12 million rows, or that production changed outside your migrations. They work well together.
Does DbProof connect to my database?
No. Capture runs in your deploy job, and checks run against a throwaway Postgres in your runner. DbProof only receives the snapshot.
Also for Flyway Prisma Drizzle Kit