RowShield
Guides

Detect Supabase schema drift after migrations

A one-time audit tells you about today. The problem with AI-assisted development is not the first mistake, it is the fortieth prompt, which drops a policy nobody re-reads.

RowShield takes a catalog snapshot on every scan and diffs it against the previous one, so a change is visible as a change rather than as a line in a list you have stopped reading.

Rules that check this

What counts as drift

Tables added or removed. Policies added, removed, or rewritten. RLS toggled on or off. A storage bucket flipped to public.

A new table with correct policies produces no findings but is still drift worth showing, and a policy edited from one safe form to another is exactly what a reviewer wants to see even though nothing is wrong.

Regression is its own state

Findings are matched across runs by a stable key, so a problem that was fixed and has come back is reported as a regression rather than as something new. That is the more alarming of the two, and the one worth interrupting someone for.

Alerts fire on transitions

Something appearing, coming back, or going away. A project that has been broken for a week pages you once. This is also what makes a retried scan idempotent: it re-reads the finding history, sees the rows already recorded, and produces no transitions.

What drift looks like in practice

Three shapes cover most of what teams eventually catch. The sprint-shaped drift: a feature branch merges on Friday, its migration recreates a table for a new column set, and the policies from March never return — caught as created findings on the next scheduled scan rather than by whichever user notices their data crossing tenants.

The restore-shaped drift: a point-in-time recovery rolls data back to Tuesday and takes schema and policies with it, resurrecting holes your team fixed weeks ago. Because RowShield matches findings across scans by stable key, the alert reads regressed — which is the accurate word for last month’s bug returning.

The environment-shaped drift: staging gains the fix, production waits on a release train, and the two catalogs quietly disagree for days. Scanning both environments makes the divergence visible instead of assumed, and settles the argument about whether "it works in staging" actually means anything this week. Keep the diff emails or webhook payloads from the first month; they become the schema biography nobody had time to write, and the fastest way to answer how any given hole arrived. Skim it before releases and after incidents; the pattern of past transitions predicts where the next one will come from better than intuition does.

Reading an alert well takes seconds once you know its parts: what changed (the object and property), how it changed (created, regressed, or resolved), and what it was before — the diff carries both sides so no one re-derives history from memory. Severity rides along from the underlying rule when drift intersects a finding class; purely structural changes stay informational. The design goal is that every alert is answerable with act, acknowledge, or ignore — and if a team finds itself routinely unable to choose among those three, the alert content, not the reader, is what needs fixing.

Frequently asked

How often does it scan?
Hourly on Indie, every 15 minutes on Team, and daily on the free plan. Snapshots are retained on each scan run so a rule change can be replayed over history.
Where do alerts go?
Slack, Discord, email, or a plain webhook, with a severity threshold per destination.

Check your project in about ten seconds

Paste a URL. No signup, no writes, nothing stored.

Run the free audit
supabase schema drift after migrationcontinuous monitoring supabase rls driftsupabase rls regression detection