landsafe

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.

.github/workflows/landsafe.yml
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.

migrations/20260716_add_plan_to_users.sql

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

  1. Install the Action

    One workflow file. Landsafe runs on every pull request that touches a .sql migration.

  2. 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.

  3. 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
Add to GitHub

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
Get Pro

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
Get Business

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

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:

AGENTS.md
## 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.