# Supabase anon key vs service role key, which one can be in your frontend

By Mark Kashef, founder of Lockpick. Published 2026-10-08, updated 2026-10-08.

The anon or publishable key belongs in the browser and the service role or secret key never does. What each one can reach, and what to do if the wrong one shipped.

The anon key, now called the publishable key, can be in your frontend. The `service_role` key, now called the secret key, can never be. Supabase says anyone can read the publishable key, so it only reaches what Row Level Security allows. Supabase says the secret key bypasses Row Level Security, so it must never leave your control.

## What can each key reach?

| Key | Postgres role | Row level security | Belongs in |
| --- | --- | --- | --- |
| `anon` or publishable | `anon`, or `authenticated` once someone signs in | Applies | Browser, mobile app, frontend code |
| `service_role` or secret | `service_role` | Skipped | Server code and Edge Functions only |

Supabase's newer secret keys do not work in a browser at all, and Supabase answers such a request with HTTP 401 Unauthorized. The older `service_role` key has no such check. Supabase is deprecating the `anon` and `service_role` keys by the end of 2026 in favour of publishable and secret keys.

## The service role key shipped. What now?

1. Rotate it in the Supabase dashboard, because anyone who saw the bundle could already have used it.
2. Move every call that used it into server code or an Edge Function.
3. Use the publishable key in the frontend, with row level security on every table it reaches.
4. Deploy and check the live site again.

## Does a working anon key mean your data is safe?

No. The anon key is only as safe as your policies. Atlas, our example app at atlas.example, ships its publishable key on purpose and relies on policies for each table. A missing grant returns a permission error, whereas a policy that matches no rows returns an empty result. So neither an empty answer nor a permission error proves that row level security is on. Check each table's grants and policies in the dashboard instead.

## Questions people ask

### Is it a problem that my anon key is visible in the browser?

No. It is designed to be public. What matters is that every table it can reach has row level security and policies that match who should read it.

### How do I tell which key is in my bundle?

Newer keys start with sb_publishable or sb_secret. Older keys are long tokens, so check which key your client code passes to createClient and compare it with the dashboard.

## Sources

- [API keys](https://supabase.com/docs/guides/api/api-keys), Supabase docs, read on 2026-10-06
