Supabase

Read and write rows

Select, insert, update, upsert and delete rows.

Guide →

/supabase/{database_id}/rest/v1/{table}

Reads and writes the same rows as the other entry point for this database. Errors use PostgREST codes.

Support matrix and client setup

Parameters and request headers

NameLocationDescription
database_idpathDatabase ID.
tablepathtable ID or name.
selectqueryComma-separated columns; supports *, aliases, JSON paths and link-based embedding. Casts, aggregates, spread and join modifiers are unsupported.
{column}queryHorizontal filter: replace {column} with a field name or JSON path, e.g. title=eq.summary. Repeat for more columns. See the filter operator matrix.
andqueryParenthesized conditions, e.g. (done.eq.false,title.neq.draft).
orqueryParenthesized alternatives; not.and and not.or are also supported.
not.andqueryNegated conjunction.
not.orqueryNegated disjunction.
orderqueryComma-separated columns with asc/desc and nullsfirst/nullslast; JSON paths allowed.
limitqueryMaximum returned rows.
offsetqueryRows to skip.
on_conflictqueryPOST upsert: id or one unique field; use Prefer: resolution=merge-duplicates or ignore-duplicates.
columnsqueryComma-separated input columns; keys outside this set are ignored.
RangeheaderGET/HEAD inclusive row interval, e.g. 0-9. Intersects limit/offset.
Range-Unitheaderitems; other units cause Range to be ignored.
PreferheaderComma-separated preferences. Unknown preferences are ignored unless handling=strict (400 PGRST122).
Acceptheaderapplication/json, /, or application/vnd.pgrst.object+json. Singular output requires exactly one row; otherwise 406 PGRST116. Other media types return 406 PGRST107; text/csv, application/geo+json and application/vnd.pgrst.plan return 400 PGRST127.
If-None-MatchheaderEntity tag from a previous GET or HEAD (weak comparison). When it matches the current ETag the response is 304 with no body.

POST accepts an object or an array of objects; PATCH accepts an object. System columns are managed by the service. Writes return no body by default; Prefer: return=representation (SDK .select()) returns rows. PATCH and DELETE affect rows matching the filters; omitting filters matches all rows.

Response headerMeaning
Content-RangeReturned range/total; total is * when no count is requested.
Preference-AppliedApplied preferences.
ETagEntity tag returned by GET/HEAD; a matching If-None-Match returns 304 with no body.
LocationNew row URL for POST with return=headers-only.

Reads normally return 200, or 206 when count is requested and only some rows are returned. A matching If-None-Match returns 304. datetime values are stored and read back in UTC with exactly three fractional digits (e.g. 2026-10-11T00:30:00.000Z); precision is milliseconds and extra fractional digits are rounded half up. POST returns 201. PATCH/DELETE return 200 with representation, otherwise 204. HEAD has no body.

Select rows

GET /supabase/{database_id}/rest/v1/{table}

const { data, error } = await supabase.from("tasks").select("*").order("title").limit(10);
if (error) throw error;
console.log(data);

Response

HTTP 200

Success; write bodies require Prefer: return=representation

application/json

NameTypeDescription
[].idstring
[].versioninteger
[].created_atstring
[].updated_atstring

application/vnd.pgrst.object+json

NameTypeDescription
idstring
versioninteger
created_atstring
updated_atstring

HTTP 206

Partial range with requested count

application/json

NameTypeDescription
[].idstring
[].versioninteger
[].created_atstring
[].updated_atstring

application/vnd.pgrst.object+json

NameTypeDescription
idstring
versioninteger
created_atstring
updated_atstring

Response example — HTTP 200

HeaderValue
content-range0-0/*
etagW/"5.1"
range-unititems
[
  {
    "id": "rec_e88fcbd357aa49c9",
    "version": 1,
    "created_at": "2026-10-11T17:42:00.094Z",
    "updated_at": "2026-10-11T17:42:00.094Z",
    "title": "Write a summary",
    "done": false
  }
]

Count rows

HEAD /supabase/{database_id}/rest/v1/{table}

const { data, error, count } = await supabase.from("tasks").select("*", { head: true, count: "exact" });
if (error) throw error;
console.log(count);

Response

HTTP 200

Success; write bodies require Prefer: return=representation

No response body is declared.

HTTP 206

Partial range with requested count

No response body is declared.

Response example — HTTP 200

HeaderValue
content-range0-0/1
preference-appliedcount=exact
etagW/"5.1"
range-unititems

No response body.

Insert rows

POST /supabase/{database_id}/rest/v1/{table}

const { data, error } = await supabase.from("tasks").insert({"title":"Write a summary","done":false}).select();
if (error) throw error;
console.log(data);

Response

HTTP 201

Success; write bodies require Prefer: return=representation

application/json

NameTypeDescription
[].idstring
[].versioninteger
[].created_atstring
[].updated_atstring

application/vnd.pgrst.object+json

NameTypeDescription
idstring
versioninteger
created_atstring
updated_atstring

Response example — HTTP 201

HeaderValue
content-range0-0/*
preference-appliedreturn=representation
range-unititems
[
  {
    "id": "rec_e88fcbd357aa49c9",
    "version": 1,
    "created_at": "2026-10-11T17:42:00.094Z",
    "updated_at": "2026-10-11T17:42:00.094Z",
    "title": "Write a summary",
    "done": false
  }
]

Update rows

PATCH /supabase/{database_id}/rest/v1/{table}

const { data, error } = await supabase.from("tasks").update({ done: true }).eq("title", "Write a summary").select();
if (error) throw error;
console.log(data);

Response

HTTP 200

Success; write bodies require Prefer: return=representation

application/json

NameTypeDescription
[].idstring
[].versioninteger
[].created_atstring
[].updated_atstring

application/vnd.pgrst.object+json

NameTypeDescription
idstring
versioninteger
created_atstring
updated_atstring

HTTP 204

Success without a body

No response body is declared.

Response example — HTTP 200

HeaderValue
content-range0-0/*
preference-appliedreturn=representation
range-unititems
[
  {
    "id": "rec_e88fcbd357aa49c9",
    "version": 2,
    "created_at": "2026-10-11T17:42:00.094Z",
    "updated_at": "2026-10-11T17:42:01.047Z",
    "title": "Write a summary",
    "done": true
  }
]

Upsert rows

POST /supabase/{database_id}/rest/v1/{table}

const { data, error } = await supabase.from("tasks").upsert({"title":"Write a summary","done":true}, { onConflict: "title" }).select();
if (error) throw error;
console.log(data);

Response

HTTP 201

Success; write bodies require Prefer: return=representation

application/json

NameTypeDescription
[].idstring
[].versioninteger
[].created_atstring
[].updated_atstring

application/vnd.pgrst.object+json

NameTypeDescription
idstring
versioninteger
created_atstring
updated_atstring

Response example — HTTP 201

HeaderValue
content-range0-0/*
preference-appliedresolution=merge-duplicates, return=representation
range-unititems
[
  {
    "id": "rec_e88fcbd357aa49c9",
    "version": 3,
    "created_at": "2026-10-11T17:42:00.094Z",
    "updated_at": "2026-10-11T17:42:01.735Z",
    "title": "Write a summary",
    "done": true
  }
]

Delete rows

DELETE /supabase/{database_id}/rest/v1/{table}

const { data, error } = await supabase.from("tasks").delete().eq("title", "Write a summary").select();
if (error) throw error;
console.log(data);

Response

HTTP 200

Success; write bodies require Prefer: return=representation

application/json

NameTypeDescription
[].idstring
[].versioninteger
[].created_atstring
[].updated_atstring

application/vnd.pgrst.object+json

NameTypeDescription
idstring
versioninteger
created_atstring
updated_atstring

HTTP 204

Success without a body

No response body is declared.

Response example — HTTP 200

HeaderValue
content-range0-0/*
preference-appliedreturn=representation
range-unititems
[
  {
    "id": "rec_e88fcbd357aa49c9",
    "version": 3,
    "created_at": "2026-10-11T17:42:00.094Z",
    "updated_at": "2026-10-11T17:42:01.735Z",
    "title": "Write a summary",
    "done": true
  }
]
Export

On this page