Real flyway migrate, against production's shape
Connect a repository and DbProof finds your V…__…sql folder, in src/main/resources/db/migration or anywhere else, 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 flyway_schema_history.
Apply one version at a time
Flyway runs with -target for each new version in turn, so a finding names the script 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 script, the line and a suggested fix.
The setup pull request runs Flyway's own Docker image, so the check needs no Java build:
- uses: dbproof/check-action@v1 with: project: your-org/billing migrations-dir: db/migration migrate-command: >- docker run --rm --network host -v "$PWD/db/migration:/flyway/sql" flyway/flyway:11-alpine -url="$DBPROOF_CHECK_JDBC_URL" -user="$DBPROOF_CHECK_USER" -password="$DBPROOF_CHECK_PASSWORD" -locations=filesystem:/flyway/sql migrate
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. DbProof suggests a backfill and a V145_1__enforce_… script that follows it.
Migration fails to apply
A hotfix already added the column in production. DbProof shows Postgres's error from Flyway's output, on the pull request.
Index built without CONCURRENTLY
Writes to a large table blocked while the index builds. The fix builds it concurrently, in a script Flyway runs outside a transaction (executeInTransaction=false).
Table rewrite on a table over 1M rows
A type change that rewrites the whole table while holding its lock.
Version used by another open pull request
Two pull requests both add V145. Whichever merges second fails on deploy.
An applied script edited
Someone changed a script production already ran, which Flyway's validation rejects on the next deploy.
Foreign key without an index
Every delete from the parent scans the child table.
Production changed outside migrations
DbProof opens a pull request with a V…__adopt_… script on the next free version, so history catches up with production.
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
flyway_schema_history, withinstalled_by, the database user, replaced before upload
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
Flyway questions
Spring Boot runs Flyway at startup. Does that work?
Checks do: they only need the migrations folder. Capture runs on a schedule every six hours, and in your deploy job if you add its two steps; capturing from application startup is coming later.
Repeatable migrations?
Yes. DbProof tracks R__ scripts in production's history, so a deploy that only changes a view isn't mistaken for drift.
Java-based migrations?
Not yet. The check applies SQL scripts; a Java migration isn't run.
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 Atlas Prisma Drizzle Kit