One Server

Docs

Access rules

Why a new table looks empty. This is where things go wrong most often on this platform, so read it first.

Access rules (RLS)

This is where things go wrong most often on this platform. You don't notice, because you get an empty list back, not an error.

What you must know

A new table is created with access rules turned on and no rules at all. With no rules, nobody can see the table. You get an empty array back, not an error.

create table notes (id uuid primary key default gen_random_uuid(), body text);
-- select with the publishable key now: []  (not an error)

Role names

They differ per project. They are not a fixed anon/authenticated. list_policies tells you the project's three real role names.

RoleWho
<ref>_anonPeople who are not signed in
<ref>_authenticatedPeople who are signed in
<ref>_service_roleThe server. Bypasses the rules entirely

SQL written for Supabase runs as it is (Supabase name translation). In run_sql, query_sql, apply_migrations, the console's SQL editor and oneend db push, public., auth. and storage. become app_<ref>., auth_<ref>. and stor_<ref>., and anon, authenticated and service_role after to/from become the project's roles. The schema in a string that names an object ('public.orders'::regclass, to_regclass('public.orders'), 'public'::regnamespace) is replaced too. The answer's translated says what was replaced. Other strings and comments are left alone; a direct connection (psql) is not translated. Everything runs with the search_path app_<ref>, auth_<ref>, public, extensions, so an unqualified create table orders or 'orders'::regclass means this project's own.

Three common rules

-- readable by anyone
create policy "public read" on notes for select to <ref>_anon using (true);

-- only the signed-in user's own rows
create policy "own rows" on notes for all to <ref>_authenticated
  using (user_id = auth_<ref>.uid());

-- signed-in users may write, but never in someone else's name
create policy "insert own" on notes for insert to <ref>_authenticated
  with check (user_id = auth_<ref>.uid());

using is checked on reads, with check on writes. Put only using on an insert and nobody can write.

How to check

Look at the rules with list_policies, and use read_rows to see what the publishable key can actually see. After creating a table or changing rules, run get_advisors to catch problems such as tables with RLS off or rules that let anyone write.

In SQL an app runs at every start (Figma Make's kv_store and the like), give an index a name and if not exists: create index if not exists kv_store_x_key_idx on kv_store_x (key text_pattern_ops);. An unnamed create index on … makes one more identical index each time it runs (_idx1, _idx2 …), and every write updates all of them. get_advisors reports them as duplicate_index with the drop index statements that keep one.

If you made a rule and the table is still empty, the role name is the most likely culprit.