Supabase RLS policy starter pack
Copy-paste RLS policies for the 5 most common Supabase table patterns: user-owned, tenant-scoped, admin-only, public-read, and audit-log. Default-deny at base.
How to use
Paste into Supabase SQL Editor. Replace {{TABLE}} and {{TENANT_COLUMN}} as needed.
Template (sql)
copy-paste, replace {{PLACEHOLDERS}}-- Default-deny baseline (apply to every RLS-enabled table)
alter table public.{{TABLE}} enable row level security;
create policy deny_all on public.{{TABLE}}
for all using (false) with check (false);
-- Pattern 1: user-owned rows
create policy users_own on public.{{TABLE}}
for all
using (auth.uid() = user_id)
with check (auth.uid() = user_id);
-- Pattern 2: tenant-scoped (multi-tenant apps)
create policy tenant_scoped on public.{{TABLE}}
for all
using (
tenant_id = (auth.jwt() ->> 'tenant')::uuid
and auth.uid() = user_id
)
with check (
tenant_id = (auth.jwt() ->> 'tenant')::uuid
and auth.uid() = user_id
);
-- Pattern 3: admin-only
create policy admin_only on public.{{TABLE}}
for all
using ((auth.jwt() ->> 'role') = 'admin')
with check ((auth.jwt() ->> 'role') = 'admin');
-- Pattern 4: public-read (rare — for reference data only)
create policy public_read on public.{{TABLE}}
for select
using (true);
-- No write policy = no one can write
-- Pattern 5: audit log (append-only)
create policy audit_append on public.{{TABLE}}
for insert
with check (auth.uid() = user_id);
create policy audit_no_update on public.{{TABLE}}
for update
using (false);
create policy audit_no_delete on public.{{TABLE}}
for delete
using (false);
create policy audit_read_own on public.{{TABLE}}
for select
using (auth.uid() = user_id);