Home / RLS / Supabase security checklist before launch

Supabase RLS · Pillar guide

Supabase security checklist before launch

Postgres 15 · Supabase✓ code tested against a real database
TL;DR

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

RLS enabled on every table
every policy scoped to auth.uid() / membership
WITH CHECK on every INSERT / UPDATE
no USING (true) anywhere
service_role key server-only
an isolation test that fails the build

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.

◆ FREE · MIT · npm + GitHub Action

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.

npx airlock-rls

Or start from nextjs-supabase-starter — auth + a table with RLS + an isolation test, so a fresh table is safe by default.

FREE PDF

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.