Home / RLS / Supabase security checklist before launch
Supabase RLS · Pillar guide
Supabase security checklist before launch
Before you launch: RLS on every table, every policy scoped to auth.uid() or membership, WITH CHECK on every write, no USING (true), service_role server-only, and an isolation test that fails the build. The full list, each linked to how to do it, is below.
01 The checklist
Run every item before you ship. Each links to the guide that shows the exact fix. If any one fails, you have a leak waiting to happen — not a maybe.
1 · RLS on every table
No exceptions, even "internal" tables. On with no policy denies everything — that's the safe starting point. → Enable RLS on a table
2 · Every policy scoped to the caller
Compare user_id to (select auth.uid()), or workspace_id to membership. → Owner-scoped policy · Workspace policy
3 · WITH CHECK on every INSERT and UPDATE
No WITH CHECK = users write rows they can't read, or reassign rows to others. → USING vs WITH CHECK
4 · No USING (true) anywhere
The permissive policy that quietly makes a table public. Audit and scope them. → Fix a permissive policy
5 · service_role key server-only
It bypasses RLS. Never in the browser, never in NEXT_PUBLIC_*. → Next.js SSR the right way
6 · An isolation test that fails the build
Prove tenant A can't read or write tenant B — in CI, on every migration. → Test tenant isolation · RLS gate in CI
02 The 30-second version
03 Make it the default, not the checklist
A checklist you run by hand gets skipped under a deadline. The durable fix is to make the safe path the default: scaffold new projects with RLS already on and an isolation test in place (nextjs-supabase-starter, supabase-saas-kit), and gate every migration in CI (airlock-rls). Then the checklist becomes something your pipeline enforces, not something you have to remember.
Catch this before it ships
airlock-rls is a CI gate that fails your build when a table ships exposed or a policy is permissive — the same class of bug, caught on the pull request instead of in prod.
Or start from nextjs-supabase-starter — auth + a table with RLS + an isolation test, so a fresh table is safe by default.
Grab the Supabase RLS cheat sheet
The golden rules, the footguns that leak in prod, correct policy snippets, and the isolation test — on one page.
FAQ
What's the single most important item?
RLS on every table. It's the one that, if you miss it, makes the table public to anyone with your anon key — the most common Supabase leak by far. Everything else refines access; this one is the boundary.
How do I keep this from regressing after launch?
Gate it in CI so a new table without RLS, or a permissive policy, fails the build — and keep an isolation test green on every migration. Enforcement beats memory; that's what turns this checklist from a one-time ritual into a guarantee.