Supabase Oct 30, 2026 Data API change: what it means for RLS
On October 30, 2026, Supabase applies its new default to all existing projects: new tables you create in the public schema are no longer exposed to the Data API (REST and GraphQL) automatically. They need an explicit GRANT. Existing tables keep their current grants and keep working. RLS does not change: a grant decides whether a role can reach a table, RLS decides which rows.
Source: Supabase changelog: Tables not exposed to Data and GraphQL API automatically (checked 2026-10-17).
Timeline (from the Supabase changelog)
- 2026-04-28: opt-in setting available when creating a new project.
- 2026-05-30: becomes the default for all new projects (gradual rollout).
- 2026-10-30: applied to all existing projects.
Supabase says Security Advisor flags affected tables until then, and that it emails owners and admins of active projects, with a final notice planned for 2026-10-23.
What changes, and what does not
- Changes: a new table in
publicno longer getsselect, insert, update, deleteforanon,authenticatedandservice_roleby default. Until you grant, the Data API answers with error42501(permission denied for table ...) and a hint naming the missingGRANT. - Does not change: existing tables keep their grants.
enable row level securityandcreate policywork exactly as before. - Not affected: apps that only use a direct Postgres connection (psql, an ORM, or an app server with a connection string), and tables in
storage,auth,realtimeor custom schemas. - Affected: anything that uses
supabase-js, the client libraries,/rest/v1/or/graphql/v1, plus migrations, CLI scripts and AI coding tools that create tables and expect them to be reachable immediately.
The real risk: copy-pasting the wrong fix
After Oct 30, the first symptom will be a 42501 error on a new table. The fastest-looking fix is a blanket grant to every role. That puts you back where you were before the change, or worse: Supabase warns that tables exposed through the Data API without RLS can be accessed by any role with matching grants (Securing your API).
So a grant to anon on a table without RLS means anyone holding your public (publishable) key, which ships in your frontend by design, can reach that table. And Supabase notes that adding policies does not take grants back (Row Level Security). Treat grant + RLS + policies as one unit, in one migration.
Safe pattern for every new table
-- 1. Enable RLS first (no policy = no rows for client roles) alter table public.your_table enable row level security; -- 2. Grant only what each role needs -- Signed-out visitors: nothing, unless the data is truly public grant select, insert, update, delete on table public.your_table to authenticated; grant select, insert, update, delete on table public.your_table to service_role; -- 3. Policies: each user sees and changes only their own rows create policy "own rows: select" on public.your_table for select to authenticated using ((select auth.uid()) = user_id); create policy "own rows: insert" on public.your_table for insert to authenticated with check ((select auth.uid()) = user_id); create policy "own rows: update" on public.your_table for update to authenticated using ((select auth.uid()) = user_id) with check ((select auth.uid()) = user_id); create policy "own rows: delete" on public.your_table for delete to authenticated using ((select auth.uid()) = user_id);
Adapt your_table and user_id to your schema. For data that really is public (for example published blog posts), grant select to anon and add a for select to anon policy that only matches the public rows. service_role bypasses RLS, so keep its key server-side (see leaked service_role key).
Audit before and after Oct 30
List which tables the client roles can reach and whether RLS is on. Any row with a grant and rowsecurity = false needs attention now.
select g.table_name, g.grantee,
string_agg(g.privilege_type, ', ' order by g.privilege_type) as privileges,
t.rowsecurity
from information_schema.role_table_grants g
join pg_tables t on t.schemaname = g.table_schema and t.tablename = g.table_name
where g.table_schema = 'public' and g.grantee in ('anon', 'authenticated')
group by g.table_name, g.grantee, t.rowsecurity
order by t.rowsecurity, g.table_name, g.grantee;
This only reads catalog metadata, never row contents. More queries in How to check if Supabase RLS is enabled.
Opt in early (optional)
Supabase documents how to adopt the new behavior on an existing project today. These statements change defaults for future objects 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;
To lock down an existing table you never meant to expose: revoke all on table public.your_table from anon, authenticated, service_role; (from the changelog). The Securing your API docs also list matching revokes for functions.
If an AI tool writes your migrations
Supabase's stated reason for the change is that agents, CLI scripts and AI platforms now create tables without a human reviewing each diff. Add this to your coding agent's instructions:
Every new table in public must ship in one migration with: enable row level security, the minimum grants per role (never a blanket grant to anon), and explicit policies for each operation using auth.uid(). Never fix a 42501 error by granting anon more than the policy needs.
FAQ
Do my existing Supabase tables stop working on October 30, 2026?
No. Supabase says existing tables keep their current grants and stay reachable. The change affects new tables created in the public schema after the change reaches your project.
Does a GRANT replace Row Level Security?
No. A grant decides whether a role can reach a table at all; RLS decides which rows it can see or change. Use both on every table exposed through the Data API.
Is it safe to run GRANT ALL to anon to fix the permission denied error?
Not on its own. Supabase warns that a table exposed through the Data API without RLS can be accessed by any role with matching grants. Grant only what each role needs, enable RLS, and add policies in the same migration.
Am I affected if I only use a direct Postgres connection?
No. Supabase says apps that only use psql, an ORM, or an app server with a connection string are not affected. It applies to the Data API (REST and GraphQL) used by supabase-js and the client libraries.
Sources
- Supabase changelog: Tables not exposed to Data and GraphQL API automatically (checked 2026-10-17)
- Supabase docs: Securing your API (checked 2026-10-17)
- Supabase docs: Row Level Security (checked 2026-10-17)
- Supabase docs: Database API 42501 errors (checked 2026-10-17)
Free, read-only, permission-gated. Nothing stored.