How-to guides
Row Level Security in Postgres: a practical guide
With supabase-js, your browser talks straight to the database API. Row Level Security (RLS) is what makes that safe: Postgres checks every row against your policies on every request.
Turn it on
Enable RLS on every table your app exposes. With RLS on and no policy, the table returns nothing, which is a safe default.
alter table todos enable row level security;Owner-only rows
create policy "Own todos" on todos
for all to authenticated
using (auth.uid() = user_id)
with check (auth.uid() = user_id);using filters which rows can be read, updated or deleted; with check validates rows being written.
Public read, owner write
create policy "Anyone can read posts" on posts
for select using (true);
create policy "Authors write posts" on posts
for insert to authenticated with check (auth.uid() = author_id);Team access
create policy "Team members read projects" on projects
for select to authenticated
using (exists (
select 1 from memberships m
where m.team_id = projects.team_id and m.user_id = auth.uid()
));Index the columns policies use (here memberships(user_id, team_id)) so checks stay fast.
Get help writing policies
Ask the McManus assistant in your Da8a project. It proposes the SQL and nothing changes until you click Apply.
Questions
Is the anon key secret?
No. It’s meant to be public; RLS policies are what protect your data.
Does the service key respect RLS?
No. It bypasses RLS, so only use it on servers and in edge functions.
Related
- Add Google and GitHub sign-in with supabase-js
- Passwordless magic link login
- Semantic search with pgvector
- Realtime database subscriptions
- Quickstart
- supabase-js client docs
Updated 2026-10-23.