# Why RLS Is Essential — Supabase

Source: https://www.skillbyai.com/en/supabase/r-why

> Public keys need database-level rules.

## Deny by default

Browsers talk to the database API directly with the anon key, so the database itself must enforce access. **Row Level Security** adds per-row conditions to every query. Once RLS is **enabled** on a table and no policy exists, the anon and authenticated roles see **no rows**: deny by default. Each request carries a JWT; Postgres runs it as role `anon` or `authenticated`, and helpers such as `auth.uid()` expose the user id from the token. Tables created through SQL may not have RLS enabled automatically, so enable it explicitly.

## The lock on every table

Because the anon key is public, Postgres policies decide which rows each request may see or change.

![Three ideas: why RLS matters, writing policies, common patterns and testing.](assets/figures/supabase/section-3-map.svg) — Figure 3.1 — Request, JWT claims, policy check, rows.

## Enable RLS and find unprotected tables

SQL.

```sql
alter table public.notes enable row level security;

-- list public tables that still have RLS off
select c.relname as table_name
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public'
  and c.relkind = 'r'
  and not c.relrowsecurity;
```

## A bouncer at every row

The anon key gets you into the building; RLS is a bouncer at every table checking your wristband (JWT) before handing over each row.

**Quiz:** With RLS enabled and no policies, what can the anon role read?

- [x] No rows
- [ ] All rows
- [ ] Only rows it inserted
- [ ] Only the first page

*Answer:* No rows. RLS is deny by default.
