On April 21, we are restricting certain SQL actions you can perform in your database’s auth, storage, and realtime schemas.
Why are we making these restrictions?
Supabase Auth, Storage, and Realtime services each rely on their respective schemas in order to function properly.
These restrictions prevent unintended side effects like third-party tooling and user defined changes altering schemas or their objects, such as migration tables and database functions, that could disrupt or break functionality.
What this means for your project
On April 21, you will no longer be able to perform the following actions on the auth, storage, and realtime schemas:
- Create tables and database functions
- Drop existing tables or database functions
- Create indexes on existing tables
- Perform destructive actions (i.e.
INSERT,UPDATE,DELETE,TRUNCATE) on the following migration tables:auth.schema_migrationsstorage.migrationsrealtime.schema_migrations
- Revoking privileges on tables in these schemas from API roles (e.g.
anon)
However, you will still have permissions to perform the following actions:
- Create foreign keys referencing tables in the
auth,storage, andrealtimeschemas - Create RLS policies and database triggers on the following tables:
auth.audit_log_entriesauth.identitiesauth.refresh_tokensauth.sessionsauth.usersstorage.bucketsstorage.migrationsstorage.objectsstorage.s3_multipart_uploadsstorage.s3_multipart_uploads_partsrealtime.messages
How to determine if you’re affected?
- Run the following query to check if you created any tables in the
auth,storage, andrealtimeschemas:
_14SET search_path = '';_14SELECT oid::regclass AS table_name_14FROM pg_class _14WHERE _14 (relnamespace = 'auth'::regnamespace AND relowner != 'supabase_auth_admin'::regrole) _14 OR (relnamespace = 'storage'::regnamespace AND relowner != 'supabase_storage_admin'::regrole) _14 OR ( _14 relnamespace = 'realtime'::regnamespace_14 AND relowner NOT IN ( _14 SELECT oid _14 FROM pg_roles _14 WHERE rolname IN ('supabase_admin', 'supabase_realtime_admin') _14 ) _14 );
- Run the following query to check if you created any database functions in the
auth,storage, andrealtimeschemas:
_14SET search_path = '';_14SELECT pg_catalog.format('%s(%s)', oid::regproc, pg_get_function_identity_arguments(oid::regproc)) AS function_name_14FROM pg_proc _14WHERE _14 (pronamespace = 'auth'::regnamespace AND proowner != 'supabase_auth_admin'::regrole) _14 OR (pronamespace = 'storage'::regnamespace AND proowner != 'supabase_storage_admin'::regrole) _14 OR ( _14 pronamespace = 'realtime'::regnamespace _14 AND proowner NOT IN ( _14 SELECT oid _14 FROM pg_roles _14 WHERE rolname IN ('supabase_admin', 'supabase_realtime_admin') _14 ) _14 );
What you need to do
If any of the above queries return a result, you must move them to either the public schema or a schema that you’ve created. Otherwise, they will be deleted.
- Here’s how you can move a table to another schema:
_10CREATE SCHEMA IF NOT EXISTS my_custom_schema;_10ALTER TABLE storage.my_custom_table SET SCHEMA my_custom_schema;
- Here’s how you can move a database function to another schema:
_10CREATE SCHEMA IF NOT EXISTS my_custom_schema;_10ALTER FUNCTION storage.custom_function() SET SCHEMA my_custom_schema;
Additionally, if you're using Migrations or Branching, you'll need to patch your migrations to move these objects to your own schemas. E.g. if you have a migration 20250101000000_add_custom_table.sql like so:
_10-- ..._10CREATE TABLE auth.my_custom_table (_10 -- id int8 ..._10);_10-- ...
Then you need to edit it locally into:
_10-- ..._10CREATE SCHEMA IF NOT EXISTS my_custom_schema;_10CREATE TABLE my_custom_schema.my_custom_table (_10 -- id int8 ..._10);_10-- ...
Then you'll need to repair the migration history on the linked project:
_10supabase migration repair --status reverted 20250101000000_10supabase migration repair --status applied 20250101000000