Postgres migration review for pull requests
Land every change safely.
Landsafe reads the migration in your pull request and reports the lock it takes, who it blocks, and the safe path. Pro adds the impact against your real table sizes and the zero-downtime rewrite, ready to paste. Before merge, where it's still cheap.
name: landsafe
on: pull_request
permissions:
contents: read
pull-requests: write
jobs:
landsafe:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: landsafe-dev/action@v1
with:
license: ${{ secrets.LANDSAFE_LICENSE }} # optional — Pro
44 rules + cross-statement checks version-aware, Postgres 11–16 deterministic — no LLM in the analysis path zero database credentials
Playground
Paste a migration. Watch it get caught.
PROThe real engine, compiled for your browser; your SQL never leaves this page. It runs in Pro mode: the paste-ready rewrites and concrete impact numbers below are the paid part. Free fires every rule with the lock profile and safe path — detection is not the paid part.
Demo snapshot: public.users 48M rows · 6.2 GB,
public.orders 12M rows · 900 MB — impact numbers are computed against these sizes.
The failure mode
Why these migrations take sites down
Postgres DDL is transactional and lock-honest: an
ALTER TABLE takes an ACCESS EXCLUSIVE lock, and that lock waits in the
same queue as every other query. The outage is rarely the statement itself — it's what queues up
around it, and how that scales with a table your staging environment has never seen at size.
Lock-queue poisoning1 slow query is enough
Your "instant" DDL waits behind one long-running query for its ACCESS EXCLUSIVE
slot, and every new SELECT queues behind your DDL. The whole table is frozen
before the migration has done any work. A lock_timeout turns that into a clean,
retryable failure.
Table-rewrite mathevery row × every index
Changing a column type (or adding one with a volatile default) makes Postgres rewrite the
entire heap and rebuild every index on it, all under ACCESS EXCLUSIVE. No reads,
no writes, for as long as that takes on your biggest table.
Passes in staging, fails in prod10k rows ≠ 48M rows
The same statement is instant on a staging table and minutes-long on the production one, because scan and rewrite time grow with the data. Only your real table sizes can tell you what a migration costs. That is exactly what the Pro snapshot feeds the analysis.
How it works
-
Install the Action
One workflow file. Landsafe runs on every pull request that touches a
.sqlmigration. -
It comments on dangerous PRs
Every risky statement gets a finding on the PR: the lock it takes, who it blocks, and the safe path. Critical findings fail the CI check.
-
Pro hands you the rewrite
With a snapshot of your table sizes (generated once with
landsafe snapshot, committed as JSON), Pro estimates the blast radius and pastes the zero-downtime rewrite into the comment, step by step with transaction boundaries marked.
Pricing
One flat price per org. No seats, no repo counting.
Per-seat schema platforms grow their bill with your team — a 10-developer team runs ~$200/mo on their paid tiers. Landsafe is $79 whatever your size: you pay for the rewrite and the number, not per person.
Free
$0
- All 44 detection rules
- PR comments on every dangerous migration
- CI check — fails on critical findings
- Unlimited repos & developers
Pro
$79/mo
- Everything in Free
- Ready-to-paste zero-downtime rewrites
- Impact estimates against your table sizes
- Unlimited repos & developers
- License key by email in one minute — verifies locally, no call to our servers
- 14-day refund, no questions
Business
$299/mo
- Everything in Pro
- Org-wide policy — repos can tighten, never loosen
- Weekly cross-repo digest
- Dashboard — trends, audit view, merged-with-criticals log
- Unlimited repos & developers
More than 100 repos, or need SSO or invoicing? pro@landsafe.dev — it reaches a human.
Across every repo
The question one PR comment can't answer
A comment knows about its own pull request. It can't tell you which PRs merged last week with critical findings unresolved — across every repo you own. Business answers that with a weekly digest and a dashboard: trends, an audit view, and the merged-with-criticals log. Both read the findings Landsafe already wrote into your own PR comments, through your own GitHub token. There is no backend: our servers never see your repos.
Architecture of trust
Built so you don't have to trust us
- No database credentials in CI. The Action reads the SQL files in the pull request. It never connects to, queries, or modifies a database. The optional Pro snapshot is a one-time, read-only catalog query you run yourself and commit as JSON.
- Advisory-only. It comments and sets a CI check. A human always merges.
- No phone-home. Analysis runs inside your CI job. License keys are Ed25519-signed and verified offline — CI keeps working even if landsafe.dev is down.
- No LLM in the analysis path. Explicit, versioned rules over documented Postgres lock semantics. Same migration in, same answer out, every time.
- Readable source. The Action that runs in your CI is public on GitHub — audit what executes before you grant it anything.
For AI agents
If an agent writes your migrations, give it a reviewer
Coding agents generate plausible DDL that ignores lock semantics — the class of mistake that
passes every test and then freezes a 48M-row table in production. Landsafe is the deterministic
check between generated SQL and your default branch. Add a stanza to your
AGENTS.md so agents know the review exists and read it:
## Database migrations
Migration PRs are reviewed by Landsafe (Postgres lock-safety analysis).
Read its PR comment before revising a migration; prefer its suggested
zero-downtime rewrite over hand-rolled DDL.
Rule reference: https://landsafe.dev/rules
Paste the stanza above into your AGENTS.md — and into CLAUDE.md too
if you use Claude Code, which reads CLAUDE.md, not AGENTS.md. Because
the Action runs on every pull request, the agent gets the same deterministic verdict a human
reviewer sees — one it can invoke but can't talk its way past.
FAQ
Which databases are supported?
Postgres only, and we say so plainly: the rules encode Postgres lock semantics and version behavior (11–16), not generic SQL patterns. Depth over breadth.
Does Landsafe touch my database?
Not from CI, ever. The Action reads the SQL files in your pull request, comments, and sets a CI check: no database credentials, nothing executed, and a human always merges. The only thing that ever touches Postgres is the optional Pro snapshot below, which you run yourself.
What's in the snapshot Pro uses?
Table names and size statistics: estimated row counts, heap bytes, index bytes. You run
landsafe snapshot "$DATABASE_URL" once yourself, from wherever you already have
access. It runs a read-only catalog query and writes a small JSON file you commit. CI reads
the file, never your database, and it never contains rows, values, or query text.
What can the digest and dashboard see?
Only what is already in your pull request comments. Landsafe embeds findings in the comment body, and the digest and dashboard read those comments back with your own GitHub token — the same data your team can already see on the PR. Nothing is sent to us, nothing is stored by us, and neither one ever reads your code or your database.
How does licensing work?
Offline. Your license is an Ed25519-signed key you drop into the
LANDSAFE_LICENSE secret, and the Action verifies the signature locally without
contacting us. Keys carry about 13 months of validity and every paid invoice emails you a
fresh one, so an active subscription never runs out of runway. If a key does expire, the
Action logs a warning and falls back to Free mode: every rule still runs, only the Pro
extras pause. It never breaks your CI.
How is this different from a plain SQL linter?
A linter flags a pattern. Landsafe tells you the lock the statement takes, who it blocks, roughly how long it holds against your actual table sizes — and then hands you the ready-to-paste zero-downtime rewrite. Impact and the fix, not just a flag.
MySQL? SQL Server?
Later, possibly — MySQL first if demand holds. Every rule ships with real lock and version semantics for its engine, so each database is a deliberate project, not a regex port.
Colophon
Landsafe is built and run by one developer. There's no sales team and no support queue; the engine, the rules, and this page get that time instead. Mail to pro@landsafe.dev lands in my inbox, and if the analysis is ever wrong about a lock, that's a bug I want to hear about.