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.

policies.sql
alter table todos enable row level security;

Owner-only rows

policies.sql
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

policies.sql
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

policies.sql
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.

Updated 2026-10-23.