# Supabase: “Could not find a relationship between the tables in the schema cache” (PGRST200)

> A Supabase select with a join fails with PGRST200: could not find a relationship between the tables in the schema cache. Add the foreign key, then reload.

Canonical: https://app369.com/fix/supabase-could-not-find-relationship-pgrst200/
Last updated: 2026-11-09

PGRST200 is the Supabase API error for a join it can’t make, because it finds no foreign key between the two tables. The API joins tables only through foreign keys it knows about. So the fix is to add that key, or to refresh the API’s copy of the schema.

**Short answer**

Add a foreign key from one table to the other, then reload the schema cache with NOTIFY pgrst, 'reload schema'. Check the table name in your select matches exactly, and that both tables are in an exposed schema. If two foreign keys link the same tables, name the one to use with table!constraint_name(...).

Rather not fix it yourself? [**App Fix Ticket**](https://app369.com/fixed-price/flutter-firebase-bug-fix/) starts with a fixed-price diagnosis, then a fixed price for the fix before any fix work.

## **Why the relationship is not found, and the fix**

1. 01 ### **There is no foreign key between the tables**
  > “The APIs will automatically detect relationships based on the foreign keys” [**Supabase, Joins and nested tables**](https://supabase.com/docs/guides/database/joins-and-nesting) A column called author_id isn’t enough on its own. The API follows foreign key constraints, not column names, so add the constraint.```
alter table posts
  add constraint posts_author_id_fkey
  foreign key (author_id) references profiles (id);
```
2. 02 ### **The schema cache is stale**
  > “Caused by stale foreign key relationships, otherwise any of the embedding resources or the relationship itself may not exist in the database.” [**Supabase, PostgREST error codes (PGRST200)**](https://supabase.com/docs/guides/api/rest/postgrest-error-codes) A foreign key added a moment ago may not be in the API’s cached schema yet. Reload it from the SQL editor, then run the query again.```
NOTIFY pgrst, 'reload schema';
```
3. 03 ### **The name in the select is wrong** The name inside select() has to match the table name exactly. A typo, a plural where the table is singular, or capital letters in a name Postgres stored in lowercase all give PGRST200.```
// table is profiles, not profile or Profiles
const { data, error } = await supabase
  .from('posts')
  .select('id, title, profiles(name)');
```
4. 04 ### **Two foreign keys link the same tables**
  > “Choose which foreign key relationship to use when multiple foreign keys match the join.” [**Supabase, Joins and nested tables**](https://supabase.com/docs/guides/database/joins-and-nesting) If posts has both author_id and editor_id pointing at profiles, the API can’t pick one and answers PGRST201 instead. Name the constraint to use, and give each join an alias.```
await supabase
  .from('posts')
  .select('id, author:profiles!posts_author_id_fkey(name), editor:profiles!posts_editor_id_fkey(name)');
```
5. 05 ### **The table is in another schema** A table in a schema the API doesn’t expose isn’t in the schema cache at all. The common case is a foreign key to auth.users: the auth schema isn’t exposed, so join through a public.profiles table that references auth.users instead. For your own schemas, expose them in the API settings.

Checked against the vendor’s docs on November 9, 2026: [Supabase docs: PostgREST error codes](https://supabase.com/docs/guides/api/rest/postgrest-error-codes); [Supabase docs: Joins and nested tables](https://supabase.com/docs/guides/database/joins-and-nesting); [Supabase troubleshooting: Reload the PostgREST schema](https://supabase.com/docs/guides/troubleshooting/refresh-postgrest-schema); [Supabase troubleshooting: Objects in an exposed schema](https://supabase.com/docs/guides/troubleshooting/postgrest-not-recognizing-objects-in-schema).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

[**All 127 Fiverr reviews**](https://app369.com/reviews/)

Related: [**Supabase “Could not find the table in the schema cache”**](https://app369.com/fix/supabase-could-not-find-table-schema-cache/) · [**Supabase “Could not find the function” (PGRST202)**](https://app369.com/fix/supabase-could-not-find-function-schema-cache/) · [**Supabase PGRST116**](https://app369.com/fix/supabase-pgrst116-single-row/) · [**Supabase PGRST204 column not found**](https://app369.com/fix/supabase-could-not-find-column-pgrst204/)

Questions

## **More on this error**

<details>

<summary>**Why does the same join work in the SQL editor? **+</summary>

SQL joins on any columns you name. The API only follows foreign keys, so a join that works in SQL can still fail from the app as PGRST200.

</details>

<details>

<summary>**Do I need a foreign key on both tables? **+</summary>

No. One foreign key, such as posts.author_id referencing profiles.id, lets you embed in both directions: profiles inside posts, or posts inside profiles.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)