Supabase Row Level Security Patterns Every Flutter Developer Should Know
Row Level Security is the real security boundary of your Supabase app — not your Flutter code. Learn the 4 RLS patterns that cover 95% of apps, with copy-paste SQL and the mistakes that leak data.
Here's the uncomfortable truth about client-side security: your Flutter code is not a security boundary. Anyone can extract your anon key from the app bundle, open a REST client, and send whatever requests they want. The only thing standing between an attacker and your users' data is Row Level Security — policies enforced inside Postgres itself, where no client trickery can reach. This guide covers the four RLS patterns that handle roughly 95% of real apps, the exact SQL for each, and the mistakes that silently leak data. It builds directly on the email auth tutorial and the storage upload tutorial — if you haven't set up auth yet, start there. How RLS actually works (60-second version) alter table todos enable row level security; — with RLS on and no policies , every query is denied. Deny-by-default. A policy is a SQL rule attached to a table, for a command ( select , insert , update , delete — or all ). USING filters which existing rows a query can see or touch. WITH CHECK validates rows being written (insert/update). auth.uid() returns the id of the currently authenticated user — null for anonymous requests. The critical mental model: your Dart code never decides who can see what. It just sends the user's JWT; Postgres applies the policies. If your app "works" only because the UI hides a button, you have no security. Pattern 1 — Users own their rows The bread and butter: todos, notes, settings — rows with an owner_id column referencing auth.users.id . alter table todos enable row level security; create policy "Owners can manage own todos" on todos for all using (auth.uid() = owner_id) with check (auth.uid() = owner_id); One policy, all four commands. Note both clauses: USING without WITH CHECK would let a user read only their rows but insert a row with someone else's…