Free workshop: build with AI without losing control of your project View the workshop →
vibebusters

← Full glossary

// glossary

Supabase secret key (service_role): the master key to your database

In short

The Supabase secret key, called service_role in the legacy key system, grants administrator access to the database and bypasses every Row Level Security policy. It is meant for server-side processing and must never appear in code that runs in the browser.

Supabase provides two families of keys. The first is public and can travel in the browser because Row Level Security policies filter it. The second is secret and overrides all those policies. It is an administration tool, very useful on the server, and it is the key that must never leave the server.

Two generations of keys

Supabase has introduced a new key system that is gradually replacing the old one:

Use New name Legacy name Can go in the browser
Public access, filtered by RLS sb_publishable_... anon Yes
Administrator access, bypasses RLS sb_secret_... service_role No

The Supabase documentation states that the secret key goes through the service_role Postgres role, which has the bypassrls attribute. Supabase announces the deprecation of the legacy anon and service_role keys by the end of 2026. Creating the new keys does not revoke the old ones: they stay active until you disable them under Settings, then API Keys.

Supabase adds a useful safeguard: a secret key used from a browser is rejected with a 401 error, detected through the User-Agent header. It is a good safety net for the new keys, and it does not cover a legacy service_role key or a key copied into a script or a mobile app.

What the secret key is for

It is designed for processing that nobody triggers directly from a screen, or that must act beyond a user's rights:

  • A payment webhook that updates a customer's subscription after a Stripe payment
  • A scheduled job that archives old data or sends a report
  • An administration function that creates an account, resets access or merges duplicates
  • A migration or bulk import of data

In a Supabase app, this processing lives in Edge Functions. Supabase provides the project keys to them as environment variables (SUPABASE_SECRET_KEYS, or the legacy SUPABASE_SERVICE_ROLE_KEY), read with Deno.env.get. The key stays on the server and never appears in the files sent to the browser.

How it ends up in the wrong place

The most common scenario in an AI-built app is very simple. A feature hits an RLS policy: the list stays empty, the save fails. The tool tries to make the feature work and finds a fix that works immediately, by using the key that knows no rules. The screen works, the problem seems solved, and the administrator key ends up in the code delivered to every visitor.

Two other paths exist: a key pasted into a .env file pushed to GitHub, and a key hard-coded in a test script left in the repository. In all three cases, the key becomes an exposed secret.

How to check your app

  1. Search the exported code for the names: service_role, sb_secret_, SERVICE_ROLE. Our guide on exporting the code explains how to get the repository if you have not already
  2. Look at the code served in the browser: developer tools, Sources or Network tab. An administrator key must not appear in any JavaScript file or request
  3. Inspect the Git history, not just the current version. A key removed from the code is still readable in older commits
  4. List the server functions that use the secret key and check that each one verifies who is calling it. An Edge Function open to everyone that uses the secret key is equivalent to a table without a policy
  5. Take stock of the active keys in the dashboard, legacy ones included

A concrete example

An inventory app built with Bolt shows a supplier dashboard. The RLS policy stops one supplier from seeing another's orders, and the administrator's summary screen stays empty. The suggested fix replaces the public key with the service_role key in the browser client. The screen fills up.

Six months later, a curious supplier opens their browser's developer tools, copies the key and can read, edit or delete all the data. The right fix would have taken an hour: an RLS policy for the administrator role, or a server function that computes the summary. The vibebusters Scan looks for exactly this kind of shortcut, in the current code and in its history.

The most common mistakes

  • The secret key in the browser's Supabase client, to get around a policy
  • The legacy service_role key never disabled after moving to the new keys
  • The key in a versioned .env file on GitHub, sometimes in a public repository
  • An Edge Function without caller checks that uses the secret key
  • The same key shared between the test environment and production

The takeaway

The secret key is a legitimate and often necessary tool. Handle it like the key to a safe: one place, on the server, with a clear list of the functions that use it and a plan to replace it. The Scan produces that inventory and, if a key has circulated, the Production Upgrade organises its replacement without interrupting the app.

// faq

The questions we keep hearing

What is the difference between the Supabase publishable key and the secret key?

The publishable key (formerly anon) is public by design and remains subject to RLS policies. The secret key (formerly service_role) uses a role that bypasses RLS: it reaches all the data and must only be used server-side.

Are the anon and service_role keys going away?

Supabase says it is deprecating the anon and service_role keys by the end of 2026, in favour of sb_publishable_ and sb_secret_ keys. Both systems work side by side, and the legacy keys stay valid until you disable them in the dashboard.

What should I do if my secret key was exposed?

Treat it as compromised: create a new key, update the server functions that use it, then revoke the old one. Next, remove the key from the code and the Git history, and check the logs for unusual access.

Check where your app's keys live

The Scan looks for keys in the code, the Git history and the configuration, then tells you which ones to replace and how to do it without downtime.

See what the Scan covers