Most apps carry authorization logic in the wrong place. It lives in the API layer as if-statements, in the frontend as conditional renders, occasionally in a middleware, and — always — a version of it eventually appears in a background job that skips the whole chain. When these versions disagree, someone reads data they shouldn't. Postgres RLS fixes this at the source.
The one-liner
Row-Level Security lets you attach an access policy to every table. Every SELECT, INSERT, UPDATE and DELETE runs through the policy before it touches a row. If the policy says no, the row isn't returned — even if the query is a curl request from a stolen anon key.
What this replaces
Every 'is this user allowed to see this?' check in your app. Every 'filter by user_id' clause you keep forgetting on some rare route. The middleware you wrote once and never look at. All of it collapses into a policy the database enforces.
The pattern
Own-row-only is the default. Every table with per-user data has a policy that says: you can see rows where owner_id = auth.uid(). Every insert has a WITH CHECK that says: the owner_id must be your uid. Every update and delete: same. Four policies per table, one shape, no exceptions.
For public reads, layer a permissive SELECT policy on top. For admin-role bypasses, use the service_role key server-side (which skips RLS). The pattern stays clean because every deviation is explicit.
Test it like a database, not a feature
Because policies are SQL, you can prove them with SQL. Set a session's role to a specific user, run the query you're worried about, and check the row count. If a policy is wrong, the test says so in one line. No mocked auth, no headless browser, no vibes.
The hidden win
Once your policies are the authority, your app code shrinks. Server actions become thin. Client fetches don't need paranoid filters. Background jobs become safe by default — a scraper using the service role bypasses RLS explicitly, and a scheduled job with a user-scoped token honors it automatically. Authorization stops being a maintenance tax.
If your access rules live in one file — a migration — then adding a new table is a policy question, not a code review question.