Home / RLS / Fix PGRST200: Could not find a relationship · Em português
Supabase · Error fix
Fix PGRST200: Could not find a relationship in the schema cache
Joining tables inside select() (embedding) works only through a foreign key. No foreign key between the two tables, no relationship. Add the foreign key (the referenced column must be a primary key or unique), reload the cache, and if there are two keys between the same tables, name the one you mean.
01 What the error says
response
{
"code": "PGRST200",
"message": "Could not find a relationship between 'books' and 'authors' in the schema cache",
"details": "Searched for a foreign key relationship between 'books' and 'authors' in the schema 'public', but no matches were found."
}
A query like supabase.from('books').select('title, authors(name)') asks the Data API to join through a foreign key. It doesn't guess joins from column names: author_id alone isn't enough.
02 Check which foreign keys exist
check.sql
select conrelid::regclass as from_table, confrelid::regclass as to_table, conname from pg_constraint where contype = 'f' and connamespace = 'public'::regnamespace order by 1;
03 Add the foreign key
migration.sql
alter table public.books add constraint books_author_id_fkey foreign key (author_id) references public.authors(id); notify pgrst, 'reload schema';
The referenced column must be a primary key or unique, otherwise Postgres refuses the constraint (there is no unique constraint matching given keys).
04 Two keys between the same tables: PGRST201
If books has both author_id and editor_id pointing to authors, the embed is ambiguous and you get PGRST201, whose hint lists the options. Name the foreign key:
// pick the relationship by constraint name supabase.from('books').select('title, author:authors!books_author_id_fkey(name)')
05 Found, but the joined rows are empty
That's RLS, not the relationship: the embedded table has its own policies, and rows the caller can't see come back as null or an empty array. Check the SELECT policy on the joined table.
Is your app leaking right now?
Paste your live URL. The scanner reads your page and its JavaScript for a Supabase service_role key, the one leak that skips every policy in this guide.
Catch this before it ships
airlock-rls is a CI gate that fails your build when a table ships exposed or a policy is permissive: the same class of bug, caught in CI against a database with your migrations applied, before it reaches prod.
Or start from nextjs-supabase-starter : auth + a table with RLS + an isolation test, so you start from a pattern that's already sealed.
Grab the Supabase RLS cheat sheet
The golden rules, the footguns that leak in prod, correct policy snippets, and the isolation test — on one page.
FAQ
Can I join tables that are in different schemas?
The foreign key can point across schemas, but both tables have to be in schemas the Data API exposes for the embed to work.
I added the foreign key and still get PGRST200.
Reload the schema cache (notify pgrst, 'reload schema'), and check the table names in the select: the embed uses table names (or the alias you give it), not column names.