Supabase
Supabase RLS, explained like you're a founder — not a DBA
Row-Level Security is the single most important switch in your Supabase project. Here's what it does, why AI tools keep leaving it off, and how to set it up in plain English.
The mental model
Your Supabase database is a filing cabinet in a public hallway. The anon key that ships in your frontend is a hallway pass — everyone who visits your app has one. RLS policies are the locks on each drawer. Without them, the hallway pass opens everything: every user's rows, every table, read and often write.
Why AI tools leave it off
An app with RLS enabled and no policies written returns no data at all — which looks broken in a demo. So generated code often works around it: RLS disabled, filtering done in the frontend with .eq('user_id', ...). That filter is a suggestion, not a rule — anyone can remove it and query the whole table.
The two-step fix
Step 1: enable RLS on every table (Supabase dashboard → table → RLS toggle, or ALTER TABLE x ENABLE ROW LEVEL SECURITY;).
Step 2: write a policy per table that scopes rows to the logged-in user:
CREATE POLICY "own rows" ON todos FOR ALL USING (auth.uid() = user_id);
That one line means: this drawer only opens for the person whose name is on the folder.
The three mistakes to avoid
- Policies on some tables, not all — attackers look for the one you forgot.
- Using the service_role key in frontend code — that key bypasses RLS entirely; it must live server-side only.
- Trusting frontend filters — if the rule isn't in the database, it isn't a rule.
A scan with VibeSafe flags the code-side patterns (service_role in frontend, client-side-only filtering) — and always confirm the RLS toggles directly in your Supabase dashboard.
3 free scans every month · Your code is never stored
Related: