ClearedToShip
high

Supabase RLS best practices

The problem

Enabling RLS is only half the job. Permissive or incorrect policies leave data exposed even with RLS 'on'. These are the practices that make Supabase row-level security actually protect your data.

Step by step

  1. 1

    Deny by default, allow explicitly

    Enable RLS on every table so access is denied by default, then add narrow policies. Never use a 'true' / allow-all policy on tables with private data.

  2. 2

    Scope policies to the user

    Use auth.uid() to limit rows to their owner, e.g. USING (auth.uid() = user_id). Write separate policies per operation (select/insert/update/delete) and use WITH CHECK on writes.

  3. 3

    Protect against privilege escalation

    Keep the service-role key server-side only — it bypasses RLS. Don't expose views or SECURITY DEFINER functions that leak data around your policies.

  4. 4

    Test as anonymous and as a user

    Verify anonymous requests return nothing and that one user cannot read or write another user's rows. Re-run the free RLS checker to confirm.

Want it verified, not just fixed?

Fixing it is step one. A ClearedToShip review confirms the fix actually holds and gives you a signed, insured clearance to launch. Join early access:

Free launch-readiness scan
Get my free scan