Free during beta · PostgreSQL 13+ · Flyway and Atlas · GitHub Actions

Catch migrations that break production before you merge

Every migration, checked against production. DbProof flags what would fail, lock or drift, using your real schema and statistics. It never reads a row.

What it catches

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.

How it works

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 }}
The console

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.

A drift item in the DbProof console: column customers.tax_id added outside migrations, the open pull request it breaks, and four ways to resolve 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.

DbProof's schema history: production's versions named after migrations, and the diff between two of them.

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.

A project's overview in DbProof: failing pull requests, open drift and an unverified deploy, under Needs attention.
Security

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_by 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 CI's secrets

Don't take our word for it: the agent is open source, so you can read every query it runs.

Deterministic, no AI

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.

FAQ

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.

Find out what your next migration does to production

Connect a repository in a few minutes. Your first capture shows the schema; your next pull request gets checked.