A GitHub App for PostgreSQL migrations
Rehearse every migration on a database that looks like production.
- PostgreSQL 14
- PostgreSQL 15
- PostgreSQL 16
- PostgreSQL 17
- golang-migrate
- Flyway
- dbmate
- Prisma
Run it for real
Measured, not guessed. Linters read your SQL. ShadowDB runs it on a throwaway PostgreSQL full of rows and records what the database actually did.
Locks, per statement. Which lock, on which table, for how long.
Seeded data. Rewrites take as long as they would in production.
- Replayed 37 base migrations
- Respected foreign keys
- Running migration…
Isolated runner. No network, no credentials, gone after the run.
Schema diff. What changed, object by object, not DDL.
TABLE orders id bigint- total numeric+ total numeric(12,2) status text+ INDEX orders_status_idx
Catch it in review
Answers before anyone merges. Every pull request that touches a migration gets a rehearsal, a verdict and a report your reviewers can read.
On the pull request
A GitHub check with the verdict, so a risky migration can't be merged by accident.
Points at the line
Every finding names the statement and the rule it broke.
Shows the safer way
Each rule explains the risk and what to write instead. Re-run after you push.
● pull_request acme/api#482 · 1 migration changed · pg16 → replaying 37 base migrations from main …………… 1.8s → seeding 1,000,000 synthetic rows into orders ……… 3.9s → running 0038_add_status.up.sql statement by statement ALTER TABLE orders ALTER COLUMN total TYPE numeric(12,2); ✗ ACCESS EXCLUSIVE on orders held 9.2s · table rewritten CREATE INDEX orders_status_idx ON orders (status); ⚠ SHARE lock blocks writes for 3.1s · SDB201 verdict: BLOCKED 2 findings · schema diff ready · check sent to PR
Checks · #482
- ShadowDB / migrations1 critical · 1 high
- ci / test2m 14s
- ci / lint41s
SDB201 · suggestedno write lock
CREATE INDEX CREATE INDEX CONCURRENTLY orders_status_idx ON orders (status);
Know the failure modes
Knows the ways a migration hurts. Each rule is checked against what really happened in the run, with a severity you can tune per project.
Thirty-two rules.
Zero guesses.
From dropped tables to unvalidated constraints, caught before merge.
32
rules in 11 categories, from destructive changes and rewrites to locks, transactions and migration history
14–17
PostgreSQL majors, each with its own runner image
0
credentials or network access inside the sandbox
Every rule explains itself
The rules reference now says, for each rule, its category and default severity, why the statement is risky on a live database, and what to write instead.
Use a production schema snapshot as the base
Upload a schema-only pg_dump and runs start from it instead of replaying every base migration. Data statements are refused at upload, so no production rows are stored.
Run authors, branch status and notifications
Runs show the commit author and message, each branch and pull request shows its latest verdict, and results can be sent to Slack or a webhook.
API tokens and API-triggered runs
Create API tokens to start runs from CI or scripts, and optionally have ShadowDB post a comment on the pull request alongside the check.
PostgreSQL 14 to 17, new rules, audit log
Runner images for every PostgreSQL major from 14 to 17, more rules, an organization audit log, and a downloadable run report.
Stop finding out in production.
Install the GitHub App, pick a repository, and your next migration PR gets a rehearsal.