Home / RLS / RLS vs app-layer authorization

Supabase RLS · Decision

RLS vs app-layer authorization: which and why

Architecture✓ code tested against a real database
TL;DR

Make RLS the security floor — it's enforced by the database and can't be bypassed by a missing WHERE. Use app-layer checks on top for UX and business rules, never as the only thing between a user and someone else's data.

01 The difference that matters

App-layer authorization lives in your code: an if (row.userId !== me) or a .eq('user_id', me) on every query. It works — until the one query that forgot the filter. That single miss is a cross-tenant breach, and it's invisible in code review because the code looks fine.

RLS lives in the database. Once a policy is on the table, every query — from any client, any endpoint, any forgotten code path — is filtered. There's no query that can accidentally skip it. That's why RLS is a boundary and app-layer checks are convenience.

02 Use RLS as the floor

03 Where app-layer still belongs

The rule of thumb: if getting it wrong leaks data, it must be in RLS. If getting it wrong is a worse experience or a broken rule, app-layer is fine.

04 Belt and suspenders

The strongest setup runs both: RLS guarantees isolation no matter what, and app-layer checks give fast, friendly feedback. If your app-layer filter and your RLS ever disagree, RLS wins — and that's the point. Prove the floor holds with an isolation test.

◆ FREE · MIT · npm + GitHub Action

Catch this before it ships

airlock-rls is a CI gate that fails your build when a table ships exposed or a policy is permissive — the same class of bug, caught on the pull request instead of in prod.

npx airlock-rls

Or start from nextjs-supabase-starter — auth + a table with RLS + an isolation test, so a fresh table is safe by default.

FREE PDF

Grab the Supabase RLS cheat sheet

The golden rules, the footguns that leak in prod, correct policy snippets, and the isolation test — on one page.

FAQ

Is RLS enough on its own?

For tenant isolation, yes — that's exactly what it's built for. You'll still want app-layer logic for UX and business rules, but you don't need app-layer checks to make data access safe once RLS is correct and tested.

Does RLS replace my API's auth?

No — you still authenticate users (Supabase Auth) and may gate whole endpoints in code. RLS handles row-level access: given an authenticated user, which rows they may touch. The two layers complement each other.