HomeGuidesSupabase anon key vs service role key

Guide

Supabase anon key vs service role key

Which Supabase key is safe in the browser, which one bypasses Row Level Security, and where each belongs in a Lovable, Bolt, or Next.js app.

3 min read

Independent notes from VibeLocked. Not a pentest, and not affiliated with the tools named below.

Supabase gives every project two kinds of API keys. One is meant for the public. The other can do anything. Mixing them up is one of the most common mistakes in apps generated by AI builders, so here is the short version.

Checked against the Supabase docs linked below on October 13, 2026.

Want to know which key your live app exposes? The Live App Scanner finds the Supabase key in your shipped JavaScript, tells you whether it is the public key or a secret one, and checks which tables it can read.

The two keys in one table

anon / publishable key service_role / secret key
Safe in browser code Yes No, never
Row Level Security Enforced Bypassed
Typical home Frontend Supabase client Server routes, Edge Functions, cron jobs
If leaked Expected to be public. Your RLS policies are the protection Full access to data exposed through the API. Rotate immediately

Supabase now also offers newer key formats, publishable keys (sb_publishable_...) and secret keys (sb_secret_...). They play the same roles: publishable replaces anon, secret replaces service_role. Older projects still show the legacy anon and service_role JWT keys.

Why the anon key is fine to ship

The anon key identifies your project and maps requests to the anon Postgres role (or the authenticated role once a user signs in). What a request can actually read or write is decided by Row Level Security policies in Postgres. If RLS is off on a table in an exposed schema, the anon key can read and write that table. So the question is never "is my anon key hidden", it is "are my policies correct". Use the Supabase RLS checklist to check. Views and SECURITY DEFINER functions can skip those policies even with the anon key, so audit them too (views and functions that bypass RLS). Also review Supabase Auth security settings (email confirm, signup limits, redirect allowlists), because open auth weakens every policy. The same anon key opens Realtime topics: use private channels and Realtime authorization for chat, presence, and live feeds. Database triggers should call realtime.send directly rather than embedding the secret key (Broadcast from the database).

Why the service role key is dangerous

The service role key maps to a role that bypasses RLS. That is useful for admin jobs, webhooks, and background work where your own server code decides who is allowed to do what. It is a disaster in a browser bundle, a public repo, or a mobile app, because anyone can extract it. For Expo and React Native apps, where each key belongs in a mobile build covers EXPO_PUBLIC_ and the server proxy that should hold secrets instead. If an AI tool suggests the service role key to get past an RLS error such as infinite recursion detected in policy, say no and fix the policy instead. Supabase Edge Functions get the key in their environment by default, so a function has to verify who is calling and check ownership before it touches the admin client (Supabase Edge Function auth).

The same goes for AI coding tools. Never put the service role key in an MCP server config; Supabase's own MCP server can be limited to one project in read-only mode instead (MCP server security).

How to check your app right now

  1. Search your code for the key names: service_role, SERVICE_ROLE, sb_secret_.
  2. Make sure no environment variable holding it starts with NEXT_PUBLIC_ or VITE_. Those prefixes put the value in the client bundle.
  3. Build the app and search the output folder (dist/, .next/static/) for the key prefix.
  4. In Lovable or Bolt projects, check which key the generated client uses. It should be the anon or publishable key.
  5. Open the Supabase dashboard and confirm RLS is enabled on every table in the public schema. The Security Advisor flags tables without it (what each Advisor finding means). To keep it that way, add a CI test that fails when a new table ships without RLS (test Supabase RLS policies in CI).

If you find a secret key anywhere public, follow the first hour after an API key leaks.

Official docs

Questions

Is the Supabase anon key a secret?

No. Supabase designs the anon key (and the newer publishable key) to be used in the browser. It is only safe when Row Level Security is enabled and has correct policies on every table exposed through the API.

Can the service role key be used in frontend code?

No. The service role key (and the newer secret key) bypasses Row Level Security. Anyone who has it can read and change all data exposed through the API. Keep it on a server, in an Edge Function, or in a secrets store.

What should I do if my service role key was in a public repo or bundle?

Treat it as compromised. Rotate or revoke it in the Supabase dashboard, update the servers that use it, and review your data and logs. Deleting the commit is not enough.