Supabase stops auto-exposing new tables on 30 October 2026
By StackSiren · Published
On 30 October 2026, Supabase switches every existing project to a new default: tables you create in the public schema are no longer exposed to the Data API automatically. It's the same behaviour new projects have had since May, when the "Automatically expose new tables" setting started being unticked by default.
Your existing tables keep working. What changes is the next table you, or Lovable, Bolt, v0 or Cursor, create. It won't be reachable from supabase-js until it has an explicit Postgres grant.
This post covers the change itself: the dates, who's affected, why Supabase is doing it, and what to update before the day. Everything comes from Supabase's 28 April 2026 changelog entry and its Securing your API docs.
What's changing
Until now, a Supabase project created with default settings granted select, insert, update and delete on every table in public to the anon, authenticated and service_role roles. A new table was reachable through the Data API (REST and GraphQL) as soon as it existed, even before you'd turned on Row Level Security.
After the change:
| Step | Before | After |
|---|---|---|
create table in public |
Reachable via the Data API straight away | Exists, but not reachable via the Data API |
grant to anon / authenticated / service_role |
Implicit, through default privileges | Required, as an explicit statement |
enable row level security |
Unchanged | Unchanged |
create policy |
Unchanged | Unchanged |
So:
- Existing tables keep their current grants and stay reachable.
- New tables in
publicneed an explicitgrantbefore the Data API can see them, however they were created: SQL Editor, migrations, the Management API, MCP, the CLI or an AI coding tool. - RLS works exactly as before. Grants decide whether a role can reach a table. RLS decides which rows it sees.
- Tables in
storage,auth,realtimeand custom schemas aren't affected.
The timeline
| Date | What happens |
|---|---|
| 28 Apr 2026 | Changelog published. Opt-in setting at project creation ("Automatically expose new tables and functions", untick it to opt in) |
| 18 May 2026 | pg_graphql no longer enabled by default |
| 30 May 2026 | New behaviour becomes the default for new projects, rolled out gradually over a few weeks |
| 23 Sep 2026 | Email: five-week notice to owners and admins of active projects |
| 23 Oct 2026 | Email: final notice, one week before |
| 30 Oct 2026 | New behaviour applied to all existing projects |
Until 30 October, Supabase's Security Advisor flags affected tables in each project and shows the SQL to fix them.
Who's affected
You need to act if any of these is true:
- Your app reads or writes
publictables through the Data API:supabase-jsor another client library, PostgREST, GraphQL, or direct requests to/rest/v1/or/graphql/v1. - Your migrations or setup scripts create tables in
publicwithoutgrantstatements. - An AI builder, CLI script or Management API call creates tables and expects them to work straight away.
For most apps built with Lovable, Bolt or v0 on Supabase, the first one applies, because the front end talks to Supabase through supabase-js.
You're not affected if your app only uses a direct Postgres connection, such as an ORM, psql or a server with a connection string.
Why Supabase is making the change
Supabase's reasoning, from the changelog: the old default worked when a human reviewed each schema change. Now "agents, CLI scripts, and AI platforms create tables too, and many of those operations do not have a human reviewing the diff." The default grants exposed every new table, "including tables a developer forgot to protect."
Explicit grants make access a deliberate decision that you can see in your migrations. They also make the difference between anon and authenticated visible, since the two usually need different privileges. For apps where an AI writes the schema, that's a real safety improvement. It also means a new step your builder has to remember.
What to do before 30 October
1. Check what's exposed today. The change doesn't fix existing tables: whatever they can reach now, they'll still reach after 30 October. Open Security Advisor and the Data API exposure badge in the Table Editor to see which tables are worth reviewing. The Supabase RLS guide ("How to audit your project") has the SQL to list tables without RLS and the grants each role has.
2. Make grants part of creating every table. Supabase says to "treat these three steps as a unit", in the same migration:
-- 1. Grant only what each role needs (leave out anon if signed-out visitors shouldn't reach it)
grant select, insert, update, delete on public.your_table to authenticated;
grant select, insert, update, delete on public.your_table to service_role;
-- 2. Turn on Row Level Security
alter table public.your_table enable row level security;
-- 3. Add the policies you need
create policy "Users read their own rows" on public.your_table
for select to authenticated using ((select auth.uid()) = user_id);
The full step-by-step version, with policies for insert, update and delete, is in the "Safe steps for every new table" section of the same guide.
3. Tell your AI builder. Supabase recommends updating your AI tool's system prompt, or adopting its agent skill, so generated migrations include grants. A prompt you can paste into Lovable, Bolt or Cursor:
Supabase no longer grants new tables in the public schema to anon/authenticated/service_role automatically.
For every table you create from now on, put these in the SAME migration:
1) explicit GRANTs with the minimum privileges each role needs (no anon grant unless the data is public);
2) ALTER TABLE ... ENABLE ROW LEVEL SECURITY;
3) policies that compare user_id to (select auth.uid()).
Never fix a "permission denied" (42501) error by granting all tables to anon or by using the service_role/secret key in client code.
Now list any tables created in this project that are missing grants, RLS or policies, and propose the migration.
4. Optionally, switch early so nothing surprises you on the day. Supabase publishes the statements to adopt the new behaviour now. They only affect future tables and sequences the postgres role creates in public. Existing tables keep their grants:
alter default privileges for role postgres in schema public
revoke select, insert, update, delete on tables from anon, authenticated, service_role;
alter default privileges for role postgres in schema public
revoke usage, select on sequences from anon, authenticated, service_role;
Then create a throwaway table, call it with your publishable key, check that the request is refused, and drop the table. Supabase's changelog also gives a rollback if you opt in early and something breaks. That rollback grants every table to every role, though, so don't run it as a quick fix after 30 October (see below).
Seeing "permission denied for table" (42501) after the change?
That's the change working as designed: a new table has no grant yet. The response's hint names the missing role and the GRANT statement it needs. Two quick fixes are tempting, and both are worse than the error:
- Granting everything to everyone, for example
grant ... on all tables in schema public to anon, authenticated. This re-exposes every table, including private ones, to anyone with your publishable key. - Switching the front end to a
service_roleorsb_secret_key. The error goes away because these keys bypass RLS, and so does all your access control. If either key has been in a deployed bundle, rotate it.
How the grant and RLS layers fit together, and the safe fix step by step: Supabase 42501 "permission denied for table": the full fix.
What StackSiren checks (and doesn't)
StackSiren is a passive, outside-in scanner. It never queries your database, so it can't see your grants or policies, and it won't tell you whether a table is missing a grant. What it can do:
- If your public code contains a Supabase publishable key or legacy
anonkey, it reminds you to check RLS (low severity). - If your HTML or same-origin JavaScript contains a legacy
service_roleJWT or ansb_secret_key (the bad quick fix above), it reports it as critical. - It also checks security headers, exposed
/.envand/.git/config, source maps and other outside-in issues.
Run a free scan →. It needs no access to your Supabase project.
FAQ
Will my app break on 30 October?
Not for existing tables: they keep their grants. Problems start with the first new table in public that doesn't have explicit grants, which Supabase points out can happen even if Security Advisor flags nothing today.
I created my project after 30 May 2026. Am I already on the new behaviour? Probably. New projects got it by default from 30 May, rolled out gradually over a few weeks. If a new table is refused until you add a grant, you're on it.
Does this change RLS? No. RLS and policies work exactly as before. Grants are a separate layer that's checked first.
Does it affect Supabase Storage, Auth or Realtime?
No. The storage, auth and realtime schemas, and any custom schemas, keep their current grants and defaults. Storage access is still controlled by policies on storage.objects.
Does the service_role / secret key need grants too?
Yes, for new tables. Supabase's docs say a missing grant returns a permission error "including for service_role". That's why Supabase's own example grants to service_role explicitly.
Is GraphQL affected?
Yes. The change covers the GraphQL API as well as REST. Separately, from 18 May 2026 pg_graphql is no longer enabled by default.
Fix guides for this topic
Platform checklists: Lovable · Bolt · v0