Guides

Supabase API keys: anon vs service_role, and which one is safe for the browser

10 min read#supabase#api-keys#rls#guide

Who this is forAnyone stuck on which Supabase key to paste into AI-generated code, who wants to know which keys are safe to expose.

TL;DR: When you create a Supabase project, you get several keys. They fall into two kinds. One is safe to expose in the browser if you have turned on row-level locking rules (RLS). The other passes through those rules entirely. This article shows how to tell the two apart, and how to check with your own eyes that the lock is really on. The most common mistake is to stop at “I got no error, so it’s fine.”

Contents

  1. Putting the key into AI-generated code
  2. Four keys, but only two types
  3. Step 1. Sign up and create a project
  4. Step 2. Get to the API keys in Settings
  5. Step 3. When you need the old key names
  6. Step 4. How to verify the lock actually works
  7. Think twice before opening the rules

Putting the key into AI-generated code

If you ask AI to “save this to a database,” it will usually wire in Supabase. So far, so good. The trouble comes after that.

Once you create a project and open the settings screen, several keys show up. The code the AI gave you has only one SUPABASE_KEY slot, and nobody tells you which one to use.

So most people do this: they try one and use whichever works. And it works. That’s the problem.

Four keys, but only two types

Key name Type OK to put in the browser?
publishable public (new name) Yes, if RLS is enabled
anon public (old name) Yes, if RLS is enabled
secret master (new name) Never
service_role master (old name) Never

Supabase is renaming its keys, which is why there seem to be four. There are only two types.

Here’s an analogy that helps.

  • A public key is a building’s lobby key card. It gets you into the lobby. Which rooms you can open from there is decided by a separate set of rules. Those rules are the RLS I mentioned earlier.
  • A master key ignores all the rules and opens every room.

Public key (publishable, anon)

  1. Where it lives Browser, app code It's fine if it shows up in the page source
  2. Permissions Only what the rules allow A lobby key card that only gets you into the lobby
  3. Prerequisite RLS must be turned on Without it, everything is open

Only safe when the rules are in place

Master key (secret, service_role)

  1. Where it lives Server, secret storage Somewhere like GitHub Actions secrets
  2. Permissions Everything A master key that opens every room
  3. Prerequisite Passes through even with RLS The rules can't stop it

Put it in the browser and all the data is exposed

The dividing point is the third box. One key runs into the rules, and the other passes through them

Step 1. Sign up and create a project

  1. Click Start your project at supabase.com.
  2. Signing in with your GitHub account is the quickest way. Email works too.
  3. If it’s your first time, it will ask you to create an organization. The organization comes before the project. The name can be anything, and you can change it later.
  4. Inside the organization, click New project.

Three things get asked when you create the project.

Item What to enter
Name You can change it later. Anything works
Region If you’re using it from Korea, choose Seoul (the South Korea region). Responses are noticeably faster
Database password This screen won’t show it again after you leave. Write it down now

After you create it, wait a few minutes. If you go looking for the keys in the meantime and see “not yet,” that’s normal and not a bug.

Paused Supabase project screen. A notice says the project is paused, all data and backups are still safe, and it can be turned back on from the dashboard. A Resume project button is visible
The paused project screen. The fact that your data is still there and the button to turn the project back on are on the same screen

Step 2. Get to the API keys in Settings

This is the step where first-timers lose the most time. You know the keys are somewhere, but you can’t find that somewhere.

  1. Click the gear icon at the very bottom of the vertical icon bar on the left of the project screen. This is Settings.
  2. In the menu that opens on the left, click API Keys.
Supabase settings screen. In the left menu under CONFIGURATION, after General, Infrastructure, and Integrations, the API Keys item is selected. On the right, a Publishable key section explains that the key is safe to use in a browser if you have enabled RLS and set policies
Where API Keys sits in the left menu. The right side is the public key area

The English sentences on screen actually give the whole answer.

Text on screen Meaning
Publishable keys can be safely shared publicly You can make this key public
This key is safe to use in a browser if you have enabled RLS If you’ve turned on RLS, you can put it in the browser
These API keys allow privileged access This key grants privileged access. Keep it on the server only

Step 3. When you need the old key names

If the sample code or example you’re following uses the names anon and service_role, look for them in the Legacy anon, service_role API keys tab on the same screen.

Legacy anon service_role tab of the Supabase API Keys screen. The anon public key carries a note that it's safe in the browser if RLS is enabled, and the service_role secret key carries a warning not to expose it because it bypasses RLS
The old-name tab. Each of the two keys has a different warning attached

Here’s what the explanatory text on this screen says.

Key What the screen says
anon (public) Safe in the browser if RLS is enabled. Going forward, it recommends using the Publishable key
service_role (secret) Can bypass RLS. Never expose it. If it leaks, it tells you to generate a new one immediately

Only the names changed; the roles are the same. Just follow the name your code asks for.

Step 4. How to verify the lock actually works

This is the most important part of this article.

When you turn on the lock (RLS) for a table, it looks locked. But you have to check directly whether it’s really locked, because a blocked request doesn’t return an error.

Here are the results of turning on the lock for a table holding 600 articles and querying the same data three ways. The policy was set to “only logged-in users can read,” and I didn’t give unauthenticated access any policy.

Key and state used for the query Response Rows visible
Master key (service_role) OK 600
Public key (anon), not logged in OK 0
Public key (anon), logged in OK 600

A query without login doesn’t return a “permission denied” error. It returns a normal result with 0 rows.

This is a problem because on screen, the two situations look identical:

  • The lock is working, so there are 0 rows.
  • The data just isn’t there, so there are 0 rows.

In short, compare the count you see with the master key against the count you see with the public key while logged out. You need to see 600 turn into 0 with your own eyes before you can say it’s locked. “No error, so it’s fine” is not verification.

Turning on the lock itself is a one-time step per table. The procedure is in Supabase’s documentation under Row Level Security. This article covers how to check that it really turned on after you’ve enabled it.

Think twice before opening the rules

If you keep the lock on, nothing works. So when you tell AI “it’s broken, fix it,” it will open the rules for you. That will work. But you need to look at what you opened.

While building a time-off request screen (annual paid leave, a standard employee benefit in Korea), if you also want to add approval, you have to give the public key write permission. Then this happens:

And the public key is sitting right there in the browser source. That means the moment you put the page online, anyone can press the approve button.

The answer is to make the rules more precise. If that’s too hard, don’t put it on the internet. A tool you use only on your own computer is still plenty useful.

The screens and key names in this article were checked on August 24, 2026. Supabase has changed key names and screen layouts before, and its pricing terms change too. If the actual screen looks different, go by the English description on Settings > API Keys. That text is always the most current.

Frequently asked questions

Is the Supabase anon or publishable key safe to use in a browser?
Yes, but only if row-level security (RLS) is turned on. Without RLS, everything is open. The secret and service_role keys must never be exposed.
How do I check that RLS is really blocking an anon key request?
Query the table with the anon key while logged out. A blocked request returns no error, only 0 rows. The dashboard table editor uses the master key, so it cannot confirm the lock.

Want the full system? The Claude Code & Codex Skills guidebook collects the skills and subagents behind this blog, from $19.