Supabase anon key vs service role key: safe?
Two keys, one rule: one may be public, the other must never leave the server. Mixing them up is the most expensive mistake in a Supabase app.
In short
The Supabase anon key (now called the publishable key) identifies your app and is safe to ship in the browser, because row-level security decides what it can reach. The service role key (now the secret key) bypasses row-level security entirely, so it belongs only on a server and must never appear in client code.
Also called: Supabase publishable key, Supabase secret key, service_role key
What can someone do with a leaked Supabase key?
The public key is only safe because row-level security stands behind it. If a table has no policies, or security is off, anyone who copies the key from your site's JavaScript can read that table. A leaked secret key is worse, because nothing stands behind it.
If the secret key ends up in the browser, there is nothing behind it at all: Supabase's documentation says it bypasses row-level security, and so must never leave your control.
| Anon / publishable key | Service role / secret key | |
|---|---|---|
| Where it lives | In the browser or app | On a server only |
| Row-level security | Applies | Bypassed |
| If it leaks | Expected; policies protect you | Full access to your data: rotate it now |
What happened to the anon and service_role key names?
Supabase now calls these keys publishable keys (they start sb_publishable_) and secret keys (they start sb_secret_). Its API keys documentation says the old anon and service_role keys are being deprecated by the end of 2026, that both systems work at the same time, and that the old keys stay valid until you disable them in the dashboard.
So creating new keys is not enough: switch the app over, then disable the legacy pair. The rule is the same under both names.
How do you check which Supabase key a Lovable app ships to the browser?
Search the code that runs in the browser for keys starting sb_secret_ or for a legacy service_role key, then confirm every exposed table has row-level security. Lovable's own security scan helps: its quick scan runs on publish and flags tables without row-level security, and its deep scan looks for secrets in source code.
- 01Find the client keyOpen the file that creates the Supabase client and check that it uses the publishable key. Our exposed key checker looks at what a live site actually sends.
- 02Move the secret key server-sideIn Edge Functions, read it from the SUPABASE_SECRET_KEYS environment variable the runtime injects, never from a value pasted into the code.
- 03Check every tableTurn on row-level security for each table in an exposed schema. With it on and no policies, the publishable key gets no data until you write policies.
- 04Rotate if it leakedFix the leak first, create a new secret key, replace it everywhere, then delete the old one.
Why is a secret key in the browser still dangerous if Supabase rejects it?
Supabase checks where a request comes from and rejects browser requests made with a secret key. That does not make a leak safe. Its documentation warns that anyone who copies the key can still use it from other tools, so a secret key that reached a browser must be replaced and deleted.
This is why the key check sits near the top of the Lovable security checklist, and why row-level security matters as much as the key itself. If you are unsure what your app exposes, the production readiness check is a quick first look.
Common questions
Is it safe to expose the Supabase anon key?
Yes, if every exposed table has row-level security enabled with the right policies. Without them, the key opens the table to anyone. Anyone can copy it from your site's JavaScript, so row-level security is what stands between it and your data. Check every table, not just the main ones.
What should I do if the service role key leaked?
Fix the cause of the leak, then create a new secret key in the Supabase dashboard, replace the old one everywhere, and only then delete it. Check your logs for access you do not recognize. Treat the leak as full access to your data, because the key bypasses row-level security.
Where should the Supabase secret key live in a Lovable app?
Only in server code you control, such as a Supabase Edge Function. There the runtime injects it as the SUPABASE_SECRET_KEYS environment variable, so it never appears in your source. Lovable's own guidance is to store keys in Secrets, because frontend code runs in the browser where anyone can read it.
Do the old anon and service_role keys stop working automatically?
No. Supabase is deprecating them by the end of 2026, but creating new publishable and secret keys does not switch the legacy pair off. Both systems work side by side until you disable the legacy keys in the dashboard. Switch the app over first, then turn them off.
Go deeper
Lovable app security checklist: is your app secure?A checklist for RLS, keys, payments and monitoring, with a way to verify each item, and what CVE-2025-48757 means for you.
Related terms
Read next
Sources
- Supabase documentation: Understanding API keys
- Supabase documentation: Row Level Security
- Lovable documentation: Security
Sources checked October 24, 2026
More on this: Production architecture & security · All glossary terms
Built something in Lovable you want people to rely on?
We are the engineers who take it the rest of the way — secured, tested, released and supported.
