The idea
A command-line tool that hooks into pre-commit and CI to catch dangerous SQL migrations before they run against production. It spins up a throwaway shadow copy of your schema (seeded with a configurable row count), applies the pending migration, and runs EXPLAIN ANALYZE on the statements it generates plus any queries you've marked as hot paths. It fails the check with a human-readable reason if it sees a full table scan on a large table, a lock that would block writes for more than a threshold, an ALTER TABLE that rewrites the whole table on Postgres, or a missing index on a new foreign key.
Why build this
Migration incidents are one of the most common causes of production outages, and they're almost always avoidable — the query planner would have told you the ADD COLUMN ... DEFAULT was going to rewrite a 40M-row table, or that the new index was going to hold an exclusive lock for ten minutes. But nobody runs EXPLAIN by hand on every migration, and ORMs (Rails, Django, Prisma, Alembic) generate SQL that's easy to not actually read. Teams already have pre-commit and CI infrastructure; they're missing a purpose-built check that understands migration-specific failure modes rather than generic SQL linting (which mostly checks style). Postgres and MySQL have both leaned harder into online schema change tooling over the last few years, which makes it easier to build a tool that can also suggest the safe alternative, not just flag the risk.
Stack sketch
- CLI in Go for a single static binary, or Rust if you want to reuse
sqlparser-rs - Postgres and MySQL support first (
pg_query/sqlparserfor parsing, nativeEXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)) - Shadow database via ephemeral Docker container (or a reusable long-lived one for speed), seeded from a schema snapshot plus optional synthetic row generation
- Rule engine as a set of composable checks (lock duration, scan type, index coverage, rewrite risk) with a YAML config for thresholds and table-size overrides
- Migration framework adapters that shell out to
alembic upgrade,rails db:migrate,prisma migrate deploy, etc. inside the shadow DB and diff before/after - GitHub Actions / GitLab CI wrapper that posts the EXPLAIN summary as a PR comment
Scope for v1
- Postgres only, one migration framework (pick Alembic or Rails, whichever has cleaner hooks)
- A fixed rule set: full table scan on tables over N rows, lock wait exceeding a configurable ms threshold,
ALTER TABLEoperations known to rewrite - Local CLI usage plus a pre-commit hook; no hosted service, no dashboard
- Shadow DB is a local Docker container the user already has running, not auto-provisioned cloud infra
- Plain-text and JSON output, no PR-comment integration yet
Where it could go
The natural next step is CI integration that posts a readable diff of "before this migration: X ms average query time on hot path Y; after: Z ms" directly on the PR, turning it into a required check teams can gate merges on. After that, a table-size-aware simulator would let teams test migrations against production-scale data without needing a full production clone, using statistics sampling to approximate cardinality. Multi-framework and multi-database support (MySQL, then a stretch to SQLite for embedded use cases) would broaden the addressable market from "Postgres shops with Alembic" to most backend teams. There's also room for a "safe rewrite" mode that automatically suggests the online-schema-change equivalent (e.g., pt-online-schema-change style batching) instead of just flagging the risk.
Watch out for
Shadow-database accuracy is the whole product — if the seeded data doesn't resemble production's cardinality and skew, the EXPLAIN output will look fine locally and still blow up in prod, so be upfront in the docs about statistics sampling from a real (anonymized) snapshot being far more reliable than synthetic seed data. The other trap is false positives on legitimately safe migrations for small tables, which will erode trust fast if the size thresholds aren't tuned per-environment from day one.