FixRLSFixRLS
  • RLS Error
  • service_role Key
  • Publishable Key
  • Anon Key
  • MCP Setup
  • Blog
Supabase Publishable Key vs Anon Key: What Actually Matters
2026/06/11

Supabase Publishable Key vs Anon Key: What Actually Matters

What matters when choosing between Supabase publishable keys and anon keys for frontend apps.

Supabase key naming can be confusing, especially if you are reading older tutorials while using a newer Supabase project.

You may see:

  • anon key
  • publishable key
  • service_role key
  • secret key

If you are building a frontend app, the main question is usually:

Which key can safely be used in the browser?

The answer depends on the key type, but the security model is bigger than the key name.


The simple rule

For frontend code:

Use the public frontend key Supabase intends for client-side access.

For backend code:

Keep secret and service role keys server-only.

Do not put server secrets in browser code.


Why the naming causes confusion

Many older Supabase examples use the anon key in frontend code.

Newer projects may emphasize publishable keys.

This can lead developers to ask:

  • Is the anon key deprecated?
  • Is the publishable key safer?
  • Can users see it?
  • Does this replace RLS?

The key point is:

A frontend key is still public. It must be paired with proper RLS policies.

Changing the key name does not remove the need for authorization rules.


What a frontend key can do

A frontend Supabase key allows the browser client to talk to Supabase.

But the database should still enforce what that client can access.

That enforcement comes from:

  • authentication state
  • RLS policies
  • storage policies
  • allowed operations
  • table design

The key opens the door to Supabase.

RLS decides which rooms the user can enter.


What should not be public

Never expose keys that can bypass user-level policies.

For example:

SUPABASE_SERVICE_ROLE_KEY=...

This belongs on the server only.

In Next.js, avoid this mistake:

NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY=...

The NEXT_PUBLIC_ prefix means it can be exposed to the browser.

That is not what you want for a secret.


A safe environment variable pattern

For frontend:

NEXT_PUBLIC_SUPABASE_URL=...
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=...

For server-only usage:

SUPABASE_URL=...
SUPABASE_SERVICE_ROLE_KEY=...

Then use the frontend key only in browser/client code.

Use the service role key only in trusted server code.


Do not use key changes to hide policy bugs

If you get this error:

new row violates row-level security policy

The fix is usually not to switch to a more powerful key.

The fix is to write the correct policy.

For example:

create policy "Users can insert their own rows"
on todos
for insert
to authenticated
with check (
  auth.uid() = user_id
);

That policy expresses the actual rule:

Users can create rows that belong to themselves.

That is better than bypassing RLS.


Practical decision tree

Ask:

1. Is this code running in the browser?

Use a public frontend key.

2. Is this code running on the server?

You may use a secret key if the operation truly needs it.

3. Is this normal user data access?

Use RLS.

4. Is this an admin operation?

Keep it server-only and narrow.


What I use as a safety check

Before shipping, I check:

  • No service_role key in frontend code
  • No secret key with NEXT_PUBLIC_
  • RLS enabled on user data tables
  • Separate policies for select, insert, update, and delete
  • Negative tests for cross-user access
  • Storage policies reviewed separately

Most production issues come from skipping one of those.


A small guide I made

I built FixRLS to help developers generate Supabase key placement guidance and RLS starting points without connecting to their project or asking for secrets.

For publishable key guidance, start here:

https://fixrls.dev/supabase-publishable-key


Final thought

The publishable key vs anon key question matters, but it is not the whole security story.

The bigger rule is:

Public keys are expected to be visible. Secret keys are not. RLS is what protects user data.


Related FixRLS page

For this specific issue, use the matching FixRLS page: https://fixrls.dev/supabase-publishable-key

All Posts

Author

avatar for FixRLS
FixRLS

Categories

  • Supabase Keys
The simple ruleWhy the naming causes confusionWhat a frontend key can doWhat should not be publicA safe environment variable patternDo not use key changes to hide policy bugsPractical decision tree1. Is this code running in the browser?2. Is this code running on the server?3. Is this normal user data access?4. Is this an admin operation?What I use as a safety checkA small guide I madeFinal thoughtRelated FixRLS page

More Posts

How I Fixed "new row violates row-level security policy" in Supabase
Supabase RLS

How I Fixed "new row violates row-level security policy" in Supabase

A practical mental model for fixing Supabase new row violates row-level security policy errors without bypassing RLS.

avatar for FixRLS
FixRLS
2026/06/06
Is It Safe to Expose Your Supabase Anon Key?
Supabase RLSSupabase Keys

Is It Safe to Expose Your Supabase Anon Key?

How to reason about visible Supabase anon keys, RLS policies, and what actually protects user data.

avatar for FixRLS
FixRLS
2026/06/10
Why You Should Never Put Your Supabase `service_role` Key in the Frontend
Supabase Keys

Why You Should Never Put Your Supabase `service_role` Key in the Frontend

Why the Supabase service_role key must stay out of browser code and what to do if it leaked.

avatar for FixRLS
FixRLS
2026/06/09

Newsletter

Join the community

Subscribe to our newsletter for the latest news and updates

FixRLSFixRLS

Copy-paste RLS SQL, key guidance, MCP guardrails, and proof-of-fix tests before launch.

Independent tool. Not affiliated with Supabase. Not a scanner. Do not paste real secrets.

Fix Kit
  • RLS insert error
  • service_role key
  • publishable key
  • anon key exposed
  • Supabase MCP setup
Safety
  • Launch Safety Pack intent
  • Safety boundaries
  • Blog
  • GitHub examples
  • FAQ
Legal
  • Privacy Policy
  • Terms of Service
© 2026 FixRLS. All Rights Reserved.
GitHub