Home / RLS / Enable Row-Level Security on a table

Supabase RLS · How-to

How to enable Row-Level Security on a Supabase table

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

Run alter table X enable row level security; — ideally in the same migration that creates the table. But RLS on with no policy denies every row, so add at least one policy in the same step. Verify with pg_class.relrowsecurity.

01 Why it matters

Every Supabase table is reachable from the browser through the anon key. Row-Level Security is the only thing between a user and everyone else's rows. RLS off = the table is public. So enabling it is not optional hardening — it's the security boundary.

02 Enable it

migration.sql

alter table notes enable row level security;

Do this in the same migration that creates the table, so a table can never exist without it. The supabase-saas-kit CLI generates migrations this way by default.

03 The gotcha — on with no policy denies everything

Enabling RLS flips the table to deny by default. With no policy, every select/insert/update/delete returns nothing or errors — the table looks "broken." That's expected: you now have to grant access explicitly. Add at least a read policy:

migration.sql

create policy "owner reads own notes" on notes for select
  using (user_id = (select auth.uid()));

See the full owner-scoped policy set for INSERT/UPDATE/DELETE.

04 Verify it's on

check.sql

select relname, relrowsecurity
from pg_class where relname = 'notes';
-- relrowsecurity = t  → RLS is on

Table owners bypass RLS by default. If you want the owner subject to it too (defense in depth), add alter table notes force row level security;.

◆ 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

Does enabling RLS break my existing queries?

It will, until you add policies — RLS on with no policy denies everything. Enable it and add the policies your app needs in the same migration, then test the queries the way your app runs them (signed in, through the client).

Do I need RLS if I only talk to the database from a server?

If that server uses the service_role key, it bypasses RLS. But the moment any table is reachable by the anon or authenticated key from the browser, RLS is the only thing protecting it. Enable it on every table regardless — it costs nothing and closes the most common leak.