Purpose
The database enforces who can see and change what, regardless of how it's accessed.
Rules
RLS enabled on every table in
public. No exceptions; a table without policies is unreadable, which is the safe default.Policies are written per operation (
select,insert,update,delete) and named"<who> <verb> <table>".Role checks call
public.current_role(); ownership checks compareauth.uid().The
anonrole getsselectonly, and only where the tool is public-read.service_rolebypasses RLS — hence 07.01.Every policy has a test (04.05): a query that must succeed and one that must fail, as each role.
Patterns
-- public read, editors write
create policy "public read pages" on pages for select to anon, authenticated using (true);
create policy "editors insert pages" on pages for insert to authenticated
with check (current_role() in ('editor','admin'));
-- owner-only rows
create policy "users read own notes" on notes for select to authenticated using (user_id = auth.uid());
-- admin-only table
create policy "admins all on settings" on settings for all to authenticated
using (current_role() = 'admin') with check (current_role() = 'admin');
Procedure — new table
Create table → enable row level security → write policies in the same migration → write the policy tests → PR.
Owner: Matt · Last reviewed: 2026-09