Guide

Supabase anon key vs service role key: which one is safe to expose?

Every Supabase project has two kinds of keys, and mixing them up is one of the most damaging mistakes in AI-built apps. One is meant to be public. The other can read and change every row in your database.

Updated · 5 min read

The public key: anon or publishable

Older projects call it the anon key; newer projects call it the publishable key and it starts with sb_publishable_. It is meant to sit in your frontend. On its own it can do only what your row-level security policies allow for someone who is not signed in.

The private key: service role or secret

Older projects call it the service_role key; newer projects call it a secret key and it starts with sb_secret_. It bypasses row-level security completely. Anyone who has it can read, change and delete everything. It belongs only on a server or in an edge function.

How to tell which one you have

New-style keys say what they are in their prefix. Legacy keys are long JWTs that look alike; the API keys page in your Supabase dashboard labels which is anon and which is service_role. Never paste a secret key into a website to decode it.

If the service key leaked

  • Create a new secret key in your Supabase project's API keys settings.
  • Move every call that needs it into a server function or edge function, set it as a server-side environment variable, and redeploy.
  • If the leaked key is a new-style secret key, delete it. If it is a legacy service_role key, first switch the frontend from the legacy anon key to the publishable key, then deactivate the legacy keys, which turns off anon and service_role together.
  • Check your database for changes you did not make.

Common questions

Is it safe to commit the anon key to GitHub?

It is designed to be public, so committing it is not a leak in itself. Keep it in an environment variable anyway so you can rotate it easily.

Why would a builder put the service key in my frontend?

Because it makes permission errors disappear. The query works because the key skips every rule, which is exactly the problem.

The checks behind this guide

Check your whole app in one go.

The Full Scan runs seven read-only checks and writes a fix prompt for every finding.

More guides