BuiltSafely

Supabase: row-level security and API keys

Last reviewed October 2026 · Sources: Supabase official docs (linked below)

Many AI app builders (including Lovable and Bolt) use Supabase or a Supabase-style Postgres database. If you only fix one thing before launch, make it this.

1. Understand the two kinds of keys

Supabase gives you a public key that is meant to be in your browser code (the anon / publishable key), and a secret key (service_role / secret key) that bypasses access rules entirely. The public key isn't a secret. Your security comes from your access rules, not from hiding that key. The secret key must never appear in frontend code, a public repo, or a prompt you share. (Supabase: API keys)

2. Turn on row-level security (RLS) for every table

RLS is a Postgres feature that decides, row by row, who can read or change data. With RLS enabled and no policies, nobody can access the table through the public API. Policies then open up exactly what each user should see. (Supabase: Row Level Security)

-- Enable RLS
alter table public.notes enable row level security;

-- Each signed-in user can read only their own notes
create policy "read own notes" on public.notes
  for select to authenticated
  using ( (select auth.uid()) = user_id );

-- ...and insert only rows that belong to them
create policy "insert own notes" on public.notes
  for insert to authenticated
  with check ( (select auth.uid()) = user_id );

3. Test it like a stranger

Create two test accounts. Signed in as user A, try to read, change, or delete user B's rows (for example by editing an ID in a request). Then try while signed out. You should get nothing back. Only test apps you own.

4. Run the Security Advisor

Supabase's database advisors flag common problems such as tables exposed without RLS. Run them before every launch. (Supabase: Database Advisors)

5. Don't forget storage and passwords

Prompt you can give your AI builder

Enable row level security on every table in the public schema. For each table, write
policies so signed-in users can only select, insert, update and delete rows where
user_id = auth.uid(). Do not use the service role key anywhere in frontend code.
List every policy you created so I can review it.

Then check the policies yourself. An AI tool can get them wrong.