The migrations that pass review and fail on deploy
Linters read SQL. DbProof applies it for real, then weighs it against how big and how full your production tables actually are.
NOT NULL on a column with nulls
Production's statistics say the column has nulls, so the constraint fails mid-deploy.
Migration fails to apply
Every migration runs against a restored copy of production's schema, not just a parser.
Index built without CONCURRENTLY
Writes to a 12M-row table blocked for as long as the index takes to build.
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 on the parent scans the child table.
Dropped column
Code still reading it breaks the moment the migration runs.
Version used by another open pull request
Two pull requests both add V145. Whichever merges second fails on deploy.
An applied migration file changed
Someone edited a migration production already ran, so its record no longer matches what's in the repository.
Drift
A change made to production outside migrations, caught on the next capture, with a pull request to adopt it into your migrations.
Set up in one pull request
No database access for us to request, no proxy in front of production. Everything runs in your GitHub Actions.
Connect a repository
Install the GitHub App and pick a repository. DbProof finds your Flyway or Atlas migrations and opens a setup pull request with two workflows.
Capture production
A step on either side of your migrations snapshots production's schema and planner statistics, with the connection string your migrations already use. It stays in your GitHub secrets.
Every pull request is checked
Your CI restores the snapshot on a throwaway Postgres and applies the pull request's migrations. DbProof weighs them against production's statistics and reports back as a check and a comment.
In your deploy job, that's a capture step on either side of your migrations. The setup pull request adds the rest:
- uses: dbproof/agent/actions/capture@v0.1.6 with: kind: pre # and post, after your migrations dbproof-url: https://app.dbproof.dev capture-token: ${{ secrets.DBPROOF_CAPTURE_TOKEN }} capture-dsn: ${{ secrets.DBPROOF_CAPTURE_DSN }}
More than a pull request comment
Every capture adds to a record of production's schema, so DbProof can also tell you what changed between deploys, when, and whether a migration made it.
Drift, caught and resolved
Someone added a column by hand during an incident. The next capture spots it, shows which open pull requests it breaks, and offers a way out: fix the pull request, adopt the change in a migration, revert it or accept it.
Production's schema, versioned
Every deploy and every drift becomes a version, named after its migration. Read any version's schema in full, or diff any two the way you'd review a pull request.
What needs attention, in one place
For each project: the pull requests whose migrations would fail on production, drift no one has resolved yet, and deploys that ran without a capture before them.
Built for teams that can't share production credentials
The agent runs where your deploys run. DbProof receives a snapshot of structure and statistics, never data.
What capture reads
- The catalog: schemas, tables, columns, indexes, constraints, views and functions
- Planner estimates: row counts, and each column's share of nulls, distinct values and width
- Your migration history table, with Flyway's
installed_byreplaced 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 CI's secrets
Don't take our word for it: the agent is open source, so you can read every query it runs.
Who verifies the verifier?
More and more migrations are written with AI. Checking them with another model only stacks one guess on another. DbProof doesn't guess: every check is fixed logic, run against real Postgres and production's real statistics. The same migration against the same production gets the same answer, every time, and your schema is never sent to a model.
Questions
Which databases and migration tools does it support?
PostgreSQL 13 and later, on RDS, Cloud SQL, Azure, Neon or your own servers, with Flyway or Atlas migrations. Checks run in GitHub Actions.
MySQL, GitLab, other CI?
Not yet: PostgreSQL and GitHub Actions today. Tell us what you use at support@dbproof.dev.
How is this different from a migration linter?
A linter reads your SQL and matches it against patterns. DbProof applies your migrations to a copy of production's schema and weighs them against production's statistics, so it knows what a linter can't: that a column already has nulls, that a table has 12 million rows, that production changed outside your migrations.
Does DbProof connect to my database?
No. The agent runs in your CI or deploy pipeline, with the connection string your migrations already use, and uploads a snapshot of structure and statistics. Your database is never reachable from DbProof.
What does the GitHub App need?
Read access to repository metadata, and write access to contents, pull requests, workflows and actions: to open the setup pull request, comment on checks, propose fixes for drift and re-run checks. No organization permissions.
How long do you keep my data?
For as long as a project is connected. Disconnecting deletes it at once, and uninstalling the App deletes an account's data after 90 days. The privacy policy has the details.
What does it cost?
Nothing during the beta.
DbProof failed against production schema V143.