Schema changes are the riskiest thing most teams ship, and the traditional answer was a person: every migration queued behind the one engineer trusted to eyeball it. This page is the reasoning behind SIXTA's answer, and what each part of the gate actually does. For setup, jump to the CI/CD walkthrough.
When one expert reviews every schema change, that expert becomes the release bottleneck: changes wait, review quality depends on who is available and how their day is going, and everyone learns to dread (or worse, quietly skip) the review. The database reliability engineering movement's answer, argued well in Campbell and Majors' Database Reliability Engineering, is to encode that expert judgment as automated checks in the pipeline, so every change gets the same rigorous review in seconds, on every push, with no queue. That is what sixta-ci is: the DBA's judgment as a pipeline stage. On GitHub it comes in two forms with one behavior: the GitHub App reviews plain .sql migrations with zero pipeline configuration, and the workflow kit covers frameworks whose migrations must be rendered in your CI (Django, Alembic, Spring Boot). Same analysis, same comment, same check either way.
A migration isn't dangerous in the abstract; it is dangerous along specific dimensions, and the gate grades every change on each of them:
The exact lock each statement takes, what it blocks (reads, writes, other DDL), and for how long. The classic outage is an ALTER that silently queues every write behind it.
Whether the operation rewrites the whole table, and what that costs in I/O and time at your table's real size.
Long operations that replicas must replay serially, opening a lag window where failover means data loss.
Changes that silently alter results or rows: lossy type changes, NULL-semantics traps, constraint changes that validate against data you didn't check.
Every finding lands on one five-point scale, and the batch verdict carries a single worst_severity. That is the field your pipeline gates on: fail at High and above by default, tune it stricter or looser per repo, or run with the gate off first to soak.
The same ALTER is a non-event on an empty table and an hour of blocked writes on a billion-row one. Free-tier verdicts use the sizes you declare in .sixta.yml hints. With Connect Pro, SIXTA reads your production state (real table sizes, server version, replication lag, table activity) read-only and on demand, and grades against that. Two escalations follow from live measurement: when the measured size puts an operation's estimated duration past a threshold, or a blocking change targets a table that is measurably hot with writes, the verdict is raised one severity step with the rationale stated in the report. A change that looks mild in the abstract gets treated as what it is on your database. The same live grounding backs the editor tools, so both surfaces sharpen together. If your database isn't reachable from the internet, a self-hosted bridge pushes the same derived context outbound from inside your network.
A gate that only says "no" teaches people to route around it. When SIXTA fails a migration, the report includes the safe execution strategy as ready-to-run SQL: CREATE INDEX CONCURRENTLY, NOT VALID then VALIDATE, gh-ost or pt-osc for MySQL table rebuilds, chosen for your engine and version. The pattern is the remedy: most dangerous migrations have a boring, well-known safe shape, and the gate hands it to you in the PR comment.
The point of the gate is not to slow shipping down; it is the opposite. Teams throttle schema changes because merging one is scary, and they batch them up, which makes each batch scarier. With a deterministic reviewer on every PR, a passing check means something, so small migrations merge routinely and the scary backlog never forms. The mechanics respect that: one batched request per pipeline run, unchanged migrations on a re-run served from cache without burning quota, and a fail-open default (SIXTA unreachable warns and passes; findings always gate) so the gate can never hold your release hostage.
Disciplined teams don't run a change they can't undo, or at least they know explicitly when a change is one-way. The CI kit audits every migration for a prepared rollback (Django backwards renders, Alembic downgrades, companion undo files for plain .sql). Grading attached rollbacks with the same analysis, and an opt-in require_rollback gate for teams that want roll-back-ready to be policy, is rolling out now. Roll-forward-only remains a legitimate choice; the point is that it should be a choice, not a surprise.
A guardrail you can't measure is a guardrail you can't defend at budget time. Every keyed verdict leaves a change record, and your pipeline can report the disposition back with POST /v1/outcome: the finding was acted upon, overridden, or the gate passed or failed. Over time that yields the number that justifies the whole practice: the share of high-risk changes caught before production, and how often the team agrees with the gate versus overrides it.
Every PR/MR comment the gate posts ends with a small badge. It is always neutral: verdicts live in the report, never in the footer. There is also a per-repository README badge with live counters ("0 unsafe migrations approved", the same metric as the benchmarks), updated after every gated run. Your job's step summary prints a ready-made snippet with your repo's badge URL; paste it into your README. The URL is keyed by an unguessable random slug, never your repository name, so the counters only become public if you choose to publish the badge. Turning the comment footer off is a Connect Pro setting.
GitHub Actions: a PR comment, findings in code scanning (SARIF), and a check gate.
- uses: sixta-systems/sixta-ci@v1
with:
engine_version: "16" # match production (verdicts are version-dependent)
GitLab: a merge-request comment, inline Code Quality findings, and a pipeline gate.
include:
- component: gitlab.com/sixta-systems/sixta-ci/sixta-review@0.8
inputs:
engine_version: "16"
Works on Django, Alembic, Flyway, and Liquibase migrations, plain .sql files (Prisma and friends), and native SQL inside Java code (@Query, JdbcTemplate, MyBatis mappers). Django and Alembic projects add a setup input; the walkthrough has the complete per-framework configs. The kit also ships a local pre-commit hook, so the same verdicts run before the push. Full setup, inputs, and troubleshooting: the CI/CD walkthrough and the CI kit repo, or find us on the GitHub Marketplace and the GitLab CI/CD Catalog.