On October 30, 2026, Supabase stops exposing new tables to its Data API by default in existing projects. If your app was built with Lovable, Bolt or Cursor, you'll likely meet this the first time you add a table, and the quickest fix your AI tool offers can make that table readable by anyone.
What changes
- From October 30, new tables you create in the
publicschema of an existing project can't be reached through the Data API (supabase-js,/rest/v1, GraphQL) until you grant access. Most new projects have worked this way since late May. - Tables you already have keep their grants and keep working.
- Apps that connect to Postgres directly are not affected.
Source: Supabase changelog
What you'll see
The first query against a new table fails with:
code: "42501"
message: "permission denied for table your_table"
hint: "Grant the required privileges to the current role with:
GRANT SELECT ON public.your_table TO anon;"
The trap
Paste that error into an AI coding tool and it will usually do what the hint says, or go further and grant everything on every table.
A grant decides whether a role can reach a table. Row-level security (RLS) decides which rows it gets. If the table has no RLS, a grant to anon makes every row readable by anyone who opens your site, because the anon key ships in your JavaScript. Grant insert, update or delete as well, and the rows become writable too.
The safe fix
Do all three steps in the same migration. Replace your_table and user_id with your table and its owner column.
-- 1. Grant only what the app needs
grant select, insert, update, delete on public.your_table to authenticated;
-- Server code (Edge Functions) that uses the service role needs it too:
grant select, insert, update, delete on public.your_table to service_role;
-- Grant select to anon only if logged-out visitors must read this table.
-- 2. Turn on row-level security
alter table public.your_table enable row level security;
-- 3. Let each user reach only their own rows
create policy "owners manage their rows"
on public.your_table for all
to authenticated
using (auth.uid() = user_id)
with check (auth.uid() = user_id);
If you hand this to your AI tool, ask it to keep the three steps together and never to use using (true) on tables that hold user data.
Check the tables you already have
It takes two minutes. Run this in the Supabase SQL Editor:
select c.relname as table_name,
c.relrowsecurity as rls_enabled,
has_table_privilege('anon', c.oid, 'select') as anon_can_read,
has_table_privilege('authenticated', c.oid, 'select') as signed_in_can_read
from pg_class c
where c.relnamespace = 'public'::regnamespace
and c.relkind in ('r', 'p')
order by rls_enabled, table_name;
-
rls_enabledfalse andanon_can_readtrue: anyone with your site's public key can read every row. -
rls_enabledfalse andsigned_in_can_readtrue: anyone who signs up can read every row. -
rls_enabledtrue: the policies decide. Make sure none of them sayusing (true)on user data.
Missing row-level security is one of the most common holes in apps built with AI tools. I review those apps before launch, and the full guide, with copy buttons for the SQL, is at liftoffreview.com/supabase-oct-30. Happy to answer questions in the comments.
Top comments (1)
The "paste the error into your AI tool" trap is real — the hint in the error message literally suggests the fix that opens the table. Two additions that make the preparation complete:
1. You can find out whether you're affected before October 30, on the real schema:
The rollback restores everything — the list of failures is your exact migration backlog before the date arrives.
2. The catalog check for the
using (true)class on tables you already have. The warning at the end is the right instinct; this is how you audit for it instead of eyeballing policies:Every row returned is a table readable by anyone holding the anon key — RLS enabled, paperwork in order, data still open. From scanning public repos, the recurring shape is the "login helper" policy: written so sign-up can check whether an email exists, accidentally exposing every column of the table (three real cases with fixes: dev.to/cekuu35/3-supabase-rls-leak...).
And for teams who'll keep adding tables after the fix:
alter default privilegesin the same migration covers tables created later, so the 42501 class stops recurring entirely. One caveat there — apg_dumpof the project re-arms the old permissive defaults, so baselines and install templates need the same treatment (that trap and the self-healing pattern: dev.to/cekuu35/supabases-default-p...).