Guide
How to secure a Supabase database
To secure a Supabase database, enable row-level security on every table, add a policy that scopes each user to their own rows, keep the service-role key on the server, and then verify from the outside that the tables are actually closed. Those four steps close the openings that expose most Supabase apps.
The steps
- Enable RLS on every table holding user or private data.
- Add a select policy matching rows to the signed-in user, for example
auth.uid() = user_id. - Do trusted writes from your server with the service-role key, never from the browser.
- Keep the service-role key out of client code entirely.
RLS on with no policy blocks everyone; RLS on with a policy scopes each user to their rows.
Verify it worked
The dashboard setting and the deployed behaviour are not the same thing until you check. Scan your live app with Plaintext, which attempts a read the way an attacker would and reports whether protected rows still come back. Confirm the table is closed before you move on.
Frequently asked
How do I secure my Supabase database?
Enable row-level security on every table, add a policy scoping each user to their own rows, keep the service-role key server-side, and verify from the outside that the tables are closed. RLS on without a policy blocks everything, so both steps are needed.
Is enabling RLS enough to secure Supabase?
Enabling RLS turns on the gate, but you also need a policy that says who may see what. RLS on with a correct policy scopes each user to their own rows; on its own it just blocks access.
Check your own app in about a minute. Paste your URL and Plaintext reads the shipped JavaScript, the public endpoints, and the database rules for the exact holes Supabase-backed apps leave open. The first scan is free.
Scan my app