Breaking Change: Tables not exposed to Data and GraphQL API automatically

Apr 28, 2026

New tables in the public schema will no longer be exposed to the Data API automatically.

When this change takes effect#

  • Starting today (April 28, 2026), you can create new Supabase projects where tables in the public schema are not exposed to the Data API and GraphQL API by default. You can enable this setting at project creation.
  • On May 18, 2026, pg_graphql will not be enabled by default. More details here.
  • On May 30, 2026 this setting becomes the default for all new projects.
  • On October 30, 2026 the setting will be applied it to all existing projects.

Once the change is rolled out to your project, new tables you create in public schema require an explicit opt-in (via a Postgres grant ) before the Data API can see them. Existing tables are not affected in your project, they keep their current grants and stay reachable. This change applies to projects that use the Data API, Supabase's auto-generated REST and GraphQL layer, which is what supabase-js and our other client libraries call. If your app reads and writes Postgres over a direct connection (via psql, ORM or an app server with a connection string), this change will not affect you.

What's changing#

Previously, when you create a Supabase project with default settings, select, insert, update, and delete are granted to every table in the public schema to the anon, authenticated and service_role roles. Every table you create becomes reachable via the Data API on creation.

From today, the project creation screen includes a setting to opt out of those default grants. When the “Default privileges for new entities” checkbox is unchecked, you opt-in to the new behavior and tables aren’t exposed to the Data API by default. On May 30, 2026 the opt-out becomes the default for all new projects.

RLS behavior remains unchanged. Grants are a separate layer: they control whether a role can access a table at all, while RLS controls which rows that role can see.

If a grant is missing, PostgREST returns a clear error rather than a silent failure:


_10
{
_10
"code": "42501",
_10
"message": "permission denied for table your_table",
_10
"hint": "Grant the required privileges to the current role with: GRANT SELECT ON public.your_table TO anon;"
_10
}

The hint shows you which role is missing which privilege, along with the GRANT needed to fix it.

Before → After#

StepBeforeAfter
Create table in publicTable is reachable via Data API on creationTable exists but is not reachable via Data API
grant to anon / authenticated / service_roleImplicit, via default privilegesRequired, explicit grant statement
alter table ... enable row level securityRemains the sameRemains the same
create policy ...Remains the sameRemains the same

Why#

When Supabase launched, a human reviewed each schema change and enabled RLS on new tables as they went. The default grants made this convenient: create a table, and it showed up in your client.

That model doesn’t scale, and it’s easy to accidentally expose new tables before you’ve secured them.Today, agents, CLI scripts, and AI platforms create tables too, and many of those operations do not have a human reviewing the diff.

Explicit grants make access a deliberate, code-level decision. The PostgREST error response above includes a precise hint, so an agent can self-correct when a grant is missing instead of producing a broken request.

Without a grant, the API cannot see the table, regardless of how you created it (SQL editor, migrations, Management API, MCP, CLI, or an AI coding tool). Postgres enforces this at the role layer, so the guarantee holds regardless of the creation path.

We’re moving the platform toward declarative code. Explicit Postgres grants are reviewable, diffable, and greppable. They also give you per-role control: anon and authenticated need different privileges in most schemas, and an explicit grant makes that difference visible in your migrations. This was always possible, now it's the default.

Currently, the default grants expose every table in public over the Data API on creation, including tables a developer forgot to protect.

This is the next step in a series of platform default changes we have shipped over the past quarter:

Who is affected#

You are unaffected if you only talk to your database over a direct Postgres connection--you can stop reading.

You need to act if any of the following is true:

  1. Your app reads or writes tables in the public schema via the Data API (PostgREST, GraphQL, supabase-js, any of the client libraries, or direct HTTP to /rest/v1/ or /graphql/v1 )
  2. Your migrations or provisioning flow create tables in public without explicit GRANT statements.
  3. Your AI coding tool, CLI script, or Management API call creates tables and expects them to be reachable over the Data API on creation.

The change reaches you on one of three dates:

  • From Today, if you opt out of the "Default privileges for new entities" setting during project creation.
  • May 30, 2026, when the new behavior becomes the default for all new projects.
  • October 30, 2026, when the new behavior is enforced on all existing projects.

Between now and then, Security Advisor will flag affected tables, and we’ll email active projects so you can review access, add grants, and verify your app.

What to do#

For new tables you want to expose via the Data API, make explicit grants part of your table-creation flow. Without an explicit GRANT , a role will not have access to the created table.

Treat these three steps as a unit. If the grant is missing, Postgres rejects the query before RLS comes into play.


_14
-- 1. Grant the privileges the role needs
_14
grant select on public.your_table to anon;
_14
grant select, insert, update, delete on public.your_table to authenticated;
_14
grant select, insert, update, delete on public.your_table to service_role;
_14
_14
-- 2. Enable RLS
_14
alter table public.your_table enable row level security;
_14
_14
-- 3. Add the policies you need
_14
create policy "users can read their own rows"
_14
on public.your_table
_14
for select
_14
to authenticated
_14
using (auth.uid() = user_id);

If you use an AI coding tool to create tables, update its system prompt or adopt the Supabase agent skill, which includes the grants step, and which we keep updated as the platform changes. Skills are easy to install, and handle grants correctly by default. Agents can self-correct from the PostgREST error hint returned as well.

If you run your own migration framework, or a platform that provisions Supabase projects for your own customers, bundle the GRANT statements alongside your ENABLE ROW LEVEL SECURITY and policy statements in the same migration.

Opting in on existing projects#

You do not have to wait for October 30. To adopt the new behavior on an existing project today, run the same revoke statements the dashboard runs at project creation.

Open the SQL Editor for your project and run:


_10
-- Stop Postgres from granting default privileges on future objects in public
_10
alter default privileges for role postgres in schema public
_10
revoke select, insert, update, delete on tables from anon, authenticated, service_role;
_10
_10
alter default privileges for role postgres in schema public
_10
revoke usage, select on sequences from anon, authenticated, service_role;

These four statements change the defaults for future tables and sequences that the postgres role creates in the public schema.

Existing objects keep their current grants, so your running app stays reachable.

From this point on, new tables you create in the public schema need explicit GRANT statements before the Data API can see them.

If you also want to tighten grants on existing tables you do not want reachable via the Data API, revoke them per table:


_10
revoke all on table public.your_table from anon, authenticated, service_role;

The Data API exposure badge in the Table Editor and the Security Advisor list the tables worth reviewing.

FAQ#

Does this affect tables in the storage, auth, realtime, or custom schemas?

No. The change touches default privileges in the public schema. Tables in storage, auth, realtime, and any custom schemas you expose via the Data API keep their current grants and their current defaults.

I opted in on an existing project, created new tables, and my app is broken. How do I roll back?

Open the SQL Editor and run two blocks.

1) Restore defaults for future tables

Future tables will now behave as they did before the revoke:


_10
alter default privileges for role postgres in schema public
_10
grant select, insert, update, delete on tables to anon, authenticated, service_role;
_10
_10
alter default privileges for role postgres in schema public
_10
grant usage, select on sequences to anon, authenticated, service_role;

2) Fix existing tables

alter default privileges only affects future objects, so tables you created since the revoke stay without grants. Grant them in bulk:


_10
grant select, insert, update, delete on all tables in schema public to anon, authenticated, service_role;
_10
grant usage, select on all sequences in schema public to anon, authenticated, service_role;

After running both blocks, your project matches the pre-revoke state. If you added tables you want to keep private, revoke those individually after the bulk grant:


_10
revoke all on table public.your_private_table from anon, authenticated, service_role;

Rollout timeline#

DateMilestoneUser action
2026-04-28Changelog published; opt-in toggle available at project creation; docs updatedTry it on a test project; adapt your provisioning flow
2026-05-30New behavior becomes the default for all new projectsNew-project workflows must include explicit GRANT statements
2026-10-30New behavior enforced on all existing projectsMigration must be complete; tables without explicit grants stop being reachable via the Data API

Communications timeline#

We email owners and admins of every active project, including projects with no Security-Advisor-flagged tables today.

After October 30, any new table created in public without an explicit grant stops being reachable via the Data API, so a project with no flagged tables today still breaks the first time someone adds a new one.

From today through October 30, the Security Advisor flags affected tables per project and shows the remediation SQL, so you do not have to hunt for them yourself.

DateChannelAudience
2026-04-28This changelog postPublic
2026-05-07April monthly newsletterAll subscribers
2026-05-13Email: first notice of the May 30 change for new projectsOwners and admins of all active projects
2026-05-27Email: final reminder before the May 30 change for new projectsOwners and admins of all active projects
2026-09-23Email: five-week notice before the October 30 change for existing projectsOwners and admins of all active projects
2026-10-23Email: final notice, one week before change for existing projectsOwners and admins of all active projects

If you have a question, create a support ticket here.

Build in a weekend, scale to millions