Database safety in CI

The place to catch a breaking database change is in the pull request, not in an alert after it ships. A dropped column, a narrowed type, or a removed enum variant merges cleanly and passes every unit test — then days later a dashboard breaks, a nightly job fails, or an API consumer starts returning 500s. Unit tests exercise your code against your schema; nothing in a normal CI run checks the schema change itself against everything that reads it.

What “database safety in CI” means here

A check that runs on every pull request and answers one question: does this change break a reader that isn’t changing? It works by building the schema the pull request would produce and comparing it to the baseline from your default branch:

  1. Stand up a throwaway database in CI and apply the pull request’s migrations.
  2. Introspect the result — tables, columns, types, nullability, constraints, enums.
  3. Diff it against the baseline captured from your default branch.
  4. Fail the build, with a comment naming each breaking change, before it can merge.

Your production database is never contacted and no row data leaves your CI. Only schema structure is read.

Breaking vs. safe

Breaking: a dropped column, table, or enum variant; a narrowed type; a column becoming NOT NULL; a removed or narrowed API response field. Safe: additive changes — a new nullable column, a widened type — reported as informational, never failing a build.

Roll it out without blocking on day one

Start in observe-only mode (fail-on-drift: false): the Check Run and pull request comment still post, so the team sees verdicts without merge friction. Turn on blocking once those verdicts have earned trust. The quickstart has the full setup, and how this differs from monitoring explains why pre-merge and post-merge tools solve different problems.