Sources
Where each rule in the tool comes from, and when we read it.
| Source | Used for | Read |
|---|---|---|
| Supabase changelog: Breaking Change: Tables not exposed to Data and GraphQL API automatically (published 2026-04-28) | New public-schema tables are not exposed to the Data API without an explicit GRANT; rollout 2026-04-28 opt-in, 2026-05-30 default for new projects, 2026-10-30 all existing projects; missing grant returns PostgREST 42501 'permission denied for table' with a GRANT hint; grant + enable RLS + policy treated as one unit; opt-in revoke SQL; rollback SQL; storage/auth/realtime/custom schemas and self-hosted not affected; communications timeline. | 2026-11-10 |
| GitHub discussion 45329 (supabase org), including maintainer replies | Same announcement as the changelog; maintainer comment of 2026-06-08: CLI v2.102.0 adds [api] auto_expose_new_tables in config.toml and recommends explicit grants in a migration, with sequence grants for serial/identity columns; maintainer comment of 2026-06-12 (re-read 2026-11-10): auto_expose_new_tables is 'a temporary migration aid and scheduled for removal on 2026-10-30', and explicit grants in migrations are the durable way. Which CLI release removes the field was not checked. | 2026-11-10 |
| Supabase docs: Securing your API | Grants decide which roles reach a table, RLS decides which rows; default privileges table (tables/functions/sequences); example GRANT statements per role; 42501 hint example; query to check default privileges (pg_default_acl); revoke default privileges SQL; what stays after disabling 'Automatically expose new tables'. | 2026-11-10 |
| Supabase docs: Row Level Security | Enable RLS, revoke all from anon and authenticated, grant back only what each role needs; public-read example (grant select to anon, authenticated + policy using (true)); per-operation policies with (select auth.uid()) = user_id, 'to authenticated', with check; a missing grant raises 42501 before any policy runs; RLS on with no policy returns no data for a publishable key; auth.uid() is null when unauthenticated; service_role bypasses RLS; a secret key bypasses RLS only without a user access token. Views bypass RLS by default; in Postgres 15 and above a view created with security_invoker = true obeys the RLS policies of its underlying tables. | 2026-11-10 |
| Supabase knowledge base: Database API 42501 errors (marked updated 2026-11-03) | 42501 causes: forbidden schema (auth, vault), custom schema, missing table-level privileges, column-level restrictions, RLS on insert/update; often reported as 401/403; query for current table privileges (information_schema.role_table_grants); log query for 42501; privileges can be changed in Integrations > Data API. | 2026-11-10 |
| Supabase docs: Postgres Roles | anon is used by the API when a user is not signed in; authenticated when signed in; service_role is for elevated access and bypasses Row Level Security. | 2026-11-10 |
| Supabase docs: Using Custom Schemas | A custom schema needs GRANT USAGE ON SCHEMA to anon, authenticated, service_role (and exposure in the API settings) before the Data API can query it. | 2026-11-10 |
| Supabase docs: Advisors | Advisors are deterministic checks that flag security issues; the Security Advisor is in the dashboard; CLI command 'supabase db advisors'. | 2026-11-10 |
| PostgreSQL manual: Sequence Manipulation Functions | nextval requires USAGE or UPDATE privilege on the sequence. | 2026-11-10 |
| PostgreSQL manual: Numeric Types, Serial Types | A serial column creates a sequence named tablename_colname_seq and uses nextval of it as the column default. Names longer than 63 bytes are shortened by makeObjectName (PostgreSQL source, src/backend/commands/indexcmds.c): the longer of table and column name is cut first and the _seq suffix is kept; confirmed against pg_get_serial_sequence in our PGlite test. | 2026-11-10 |
| PostgreSQL manual: CREATE POLICY | Permissive policies that apply to a query are combined with OR; policies are permissive by default. | 2026-11-10 |
| PostgreSQL manual: DROP POLICY | DROP POLICY IF EXISTS does not raise an error when the policy is missing; with RLS enabled and no policy, the default-deny policy applies. | 2026-11-10 |
| PostgreSQL manual: Privileges | Meaning of SELECT, INSERT, UPDATE, DELETE and USAGE privileges on tables and sequences. EXECUTE allows calling a function or procedure and is the only privilege that applies to them. | 2026-11-10 |
| Lovable docs: Supabase integration | Lovable writes the SQL, shows it to the user and asks for approval in the project chat before running it; the page does not mention grants or 42501. | 2026-11-10 |
| Bolt help: Supabase integration | The article does not describe how migrations are applied and does not mention grants, RLS or 42501 (checked; nothing to quote). | 2026-11-10 |
| Our own test: generated SQL run against PGlite (Postgres compiled to WebAssembly) Licence: Apache-2.0 (dev dependency only, not shipped in the site) | Empirical checks in test/unit/postgres.test.mjs: 42501 before the fix; public read, owner only and private behave as described; serial inserts fail with 'permission denied for sequence' without a sequence grant; identity inserts work without one; rollback returns tables to the 42501 state; the error for a mixed-case table prints the name unquoted ('permission denied for table UserProfiles'); the error for a view says 'permission denied for view' and RLS cannot be enabled on a view; a policy comparing auth.uid() with a text column fails with 'operator does not exist: uuid = text'; an explicit default nextval('seq') needs a grant on that sequence; long serial sequence names match pg_get_serial_sequence. Not a hosted Supabase project. | 2026-11-10 |
| Albert Sans variable font (latin subset), via @fontsource-variable/albert-sans Licence: SIL Open Font License 1.1 | Font file shipped in the site: assets/albert-sans.woff2. | 2026-11-10 |
| Fira Code 400 (latin subset), via @fontsource/fira-code Licence: SIL Open Font License 1.1 | Font file shipped in the site: assets/fira-code.woff2. | 2026-11-10 |
| Playwright (test tool only, not shipped) Licence: Apache-2.0 (dev dependency only) | End-to-end test runner. | 2026-11-10 |
| PostgreSQL manual: Lexical Structure, String Constants With C-Style Escapes | In an E'...' string a backslash escapes the next character, so \' does not end the string; ordinary '...' strings treat backslash literally (standard_conforming_strings on). | 2026-11-10 |
| PostgreSQL manual: Lexical Structure, Identifiers and Key Words | An identifier begins with a letter or an underscore, and letters include letters with diacritical marks and non-Latin letters; later characters may also be digits or dollar signs. Unquoted names are folded to lower case. | 2026-11-10 |
| PostgreSQL source: downcase_identifier in src/backend/parser/scansup.c | Folding an unquoted name to lower case is ASCII-only for 7-bit characters; a character with the high bit set is changed only in a single-byte encoding, so in a UTF-8 database letters outside ASCII stay as typed. Checked in our Postgres test. | 2026-11-10 |
| PostgreSQL manual: ALTER TABLE | The action forms the tool follows: ADD [ COLUMN ] [ IF NOT EXISTS ], DROP [ COLUMN ] [ IF EXISTS ], ALTER [ COLUMN ] ... [ SET DATA ] TYPE, ALTER [ COLUMN ] ... SET DEFAULT, RENAME [ COLUMN ], RENAME TO, SET SCHEMA, and several actions in one statement separated by commas. Dropping a column also drops what depends on it inside the table. | 2026-11-10 |
| PostgreSQL source: row level security error messages in src/backend/executor/execMain.c | A row refused by a policy is reported with the insufficient-privilege code (42501) and a message that starts with new row violates row-level security policy and names the table, which is a policy problem and not a missing grant. Checked in our Postgres test. | 2026-11-10 |
| PostgreSQL source: permission denied messages in src/backend/catalog/aclchk.c | Postgres prints a separate permission denied message per object kind (table, view, sequence, schema, function, procedure and others), followed by the object name without its schema. | 2026-11-10 |
| IndexNow documentation | The key is 8 to 128 characters from a-z, A-Z, 0-9 and dashes, and is proven by a text file named after the key at the site root that holds the key. | 2026-11-10 |
| PostgreSQL manual: INSERT | INSERT needs INSERT privilege; ON CONFLICT DO UPDATE also needs UPDATE; every form of ON CONFLICT needs SELECT on columns that are read; RETURNING needs SELECT on the returned columns. | 2026-11-10 |
| PostgreSQL manual: ALTER DEFAULT PRIVILEGES | Default privileges apply to objects created by the target role (or the current role); at creation time only the creating role's defaults count; a per-schema revoke cannot remove a global default. | 2026-11-10 |
| PostgreSQL manual: CREATE VIEW | With security_invoker the caller needs privileges on the view and on its base relations, and the caller's row level security policies apply; without it the view owner's privileges and policies are used. | 2026-11-10 |
| PostgreSQL manual: CREATE FUNCTION | Execute privilege is granted to PUBLIC by default for newly created functions. | 2026-11-10 |
| PostgREST documentation source: Errors (docs/references/errors.rst, main branch) | HTTP status per Postgres error code (42501: 403 if authenticated, else 401; 42P01 and 42883: 404; 23503 and 23505: 409) and the PGRST1xx, 2xx and 3xx codes with their descriptions; example PGRST205 body. | 2026-11-10 |
| PostgREST source: Error.hs (src/library/PostgREST/Error.hs, main branch) | JWT error codes in code: a token that cannot be decoded is PGRST301, a failed claims check is PGRST303, and an expired token is a claims error with the message "JWT expired". | 2026-11-10 |
| Supabase docs: Understanding API keys | Publishable key resolves to anon (no signed-in user) or authenticated (signed-in user); secret key resolves to service_role, which has BYPASSRLS; a missing grant returns a permission error including for service_role; legacy anon and service_role keys are being deprecated by the end of 2026. | 2026-11-10 |
| Supabase docs: Prisma | The guide creates a custom database user named prisma with privileges on the public schema; if Prisma is used alone the Data API can be turned off. | 2026-11-10 |
| splinter (Supabase Postgres linter): lint documentation, main branch | Names, levels and one-line summaries of lints 0001 to 0030; lint 0010 recommends security_invoker views; lints 0026 to 0029 describe objects reachable by anon or authenticated. | 2026-11-10 |
| Supabase JavaScript client reference: insert, update, upsert, delete | Inserted, updated, upserted and deleted rows are not returned by default; chaining .select() returns them. | 2026-11-10 |
| Supabase docs: Database Functions | Any role can call a new function by default; revoke execute from public and from the restricted role, then grant execute to the roles that call it, including helper functions used in policies. | 2026-11-10 |
| Our own test: the behaviour the reference pages describe, run against PGlite Licence: Apache-2.0 / PostgreSQL License (PGlite); test tool only, not shipped | Empirical checks in test/unit/reference.test.mjs: privileges each statement needs; service_role without a grant; default privileges by creating role; ACL of a new table after the revoke; views with and without security_invoker; function execute revokes; schema usage; insert with returning under row level security; the audit query. | 2026-11-10 |
What is not verified
- We have not seen an official post confirming that the 2026-10-30 step completed on every existing project. The date is the one Supabase scheduled.
- The generated SQL was run against PGlite (Postgres in WebAssembly) set up to mimic the roles of a Supabase project. It was not run against a hosted Supabase project.
- Bolt and Replit steps are not documented in sources we could read, so those pages give only the database-side fix.
- Whether identity columns ever need a sequence grant on hosted projects. They did not in our test.