# Read and write rows (/en/docs/api/compatible/supabase/tables)



[Guide →](/en/docs/developers/services/database/quickstart)

`/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](/en/docs/api/compatible/supabase)

## Parameters and request headers [#parameters-and-request-headers]

| Name | Location | Description |
| --- | --- | --- |
| database_id | path | Database ID. |
| table | path | table ID or name. |
| select | query | Comma-separated columns; supports *, aliases, JSON paths and link-based embedding. Casts, aggregates, spread and join modifiers are unsupported. |
| &#123;column&#125; | query | Horizontal filter: replace &#123;column&#125; with a field name or JSON path, e.g. title=eq.summary. Repeat for more columns. See the filter operator matrix. |
| and | query | Parenthesized conditions, e.g. (done.eq.false,title.neq.draft). |
| or | query | Parenthesized alternatives; not.and and not.or are also supported. |
| not.and | query | Negated conjunction. |
| not.or | query | Negated disjunction. |
| order | query | Comma-separated columns with asc/desc and nullsfirst/nullslast; JSON paths allowed. |
| limit | query | Maximum returned rows. |
| offset | query | Rows to skip. |
| on_conflict | query | POST upsert: id or one unique field; use Prefer: resolution=merge-duplicates or ignore-duplicates. |
| columns | query | Comma-separated input columns; keys outside this set are ignored. |
| Range | header | GET/HEAD inclusive row interval, e.g. 0-9. Intersects limit/offset. |
| Range-Unit | header | items; other units cause Range to be ignored. |
| Prefer | header | Comma-separated preferences. Unknown preferences are ignored unless handling=strict (400 PGRST122). |
| Accept | header | application/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-Match | header | Entity 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 header | Meaning |
| --- | --- |
| Content-Range | Returned range/total; total is * when no count is requested. |
| Preference-Applied | Applied preferences. |
| ETag | Entity tag returned by GET/HEAD; a matching If-None-Match returns 304 with no body. |
| Location | New 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 [#select-rows]

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

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

### Response [#response]

#### HTTP 200 [#http-200]

Success; write bodies require Prefer: return=representation

**application/json**

| Name | Type | Description |
| --- | --- | --- |
| [].id | string |  |
| [].version | integer |  |
| [].created_at | string |  |
| [].updated_at | string |  |

**application/vnd.pgrst.object+json**

| Name | Type | Description |
| --- | --- | --- |
| id | string |  |
| version | integer |  |
| created_at | string |  |
| updated_at | string |  |

#### HTTP 206 [#http-206]

Partial range with requested count

**application/json**

| Name | Type | Description |
| --- | --- | --- |
| [].id | string |  |
| [].version | integer |  |
| [].created_at | string |  |
| [].updated_at | string |  |

**application/vnd.pgrst.object+json**

| Name | Type | Description |
| --- | --- | --- |
| id | string |  |
| version | integer |  |
| created_at | string |  |
| updated_at | string |  |

Response example — HTTP 200

| Header | Value |
| --- | --- |
| content-range | 0-0/* |
| etag | W/"5.1" |
| range-unit | items |

```json
[
  {
    "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 [#count-rows]

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

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

### Response [#response-1]

#### HTTP 200 [#http-200-1]

Success; write bodies require Prefer: return=representation

No response body is declared.

#### HTTP 206 [#http-206-1]

Partial range with requested count

No response body is declared.

Response example — HTTP 200

| Header | Value |
| --- | --- |
| content-range | 0-0/1 |
| preference-applied | count=exact |
| etag | W/"5.1" |
| range-unit | items |

No response body.

## Insert rows [#insert-rows]

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

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

### Response [#response-2]

#### HTTP 201 [#http-201]

Success; write bodies require Prefer: return=representation

**application/json**

| Name | Type | Description |
| --- | --- | --- |
| [].id | string |  |
| [].version | integer |  |
| [].created_at | string |  |
| [].updated_at | string |  |

**application/vnd.pgrst.object+json**

| Name | Type | Description |
| --- | --- | --- |
| id | string |  |
| version | integer |  |
| created_at | string |  |
| updated_at | string |  |

Response example — HTTP 201

| Header | Value |
| --- | --- |
| content-range | 0-0/* |
| preference-applied | return=representation |
| range-unit | items |

```json
[
  {
    "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 [#update-rows]

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

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

### Response [#response-3]

#### HTTP 200 [#http-200-2]

Success; write bodies require Prefer: return=representation

**application/json**

| Name | Type | Description |
| --- | --- | --- |
| [].id | string |  |
| [].version | integer |  |
| [].created_at | string |  |
| [].updated_at | string |  |

**application/vnd.pgrst.object+json**

| Name | Type | Description |
| --- | --- | --- |
| id | string |  |
| version | integer |  |
| created_at | string |  |
| updated_at | string |  |

#### HTTP 204 [#http-204]

Success without a body

No response body is declared.

Response example — HTTP 200

| Header | Value |
| --- | --- |
| content-range | 0-0/* |
| preference-applied | return=representation |
| range-unit | items |

```json
[
  {
    "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 [#upsert-rows]

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

```typescript
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 [#response-4]

#### HTTP 201 [#http-201-1]

Success; write bodies require Prefer: return=representation

**application/json**

| Name | Type | Description |
| --- | --- | --- |
| [].id | string |  |
| [].version | integer |  |
| [].created_at | string |  |
| [].updated_at | string |  |

**application/vnd.pgrst.object+json**

| Name | Type | Description |
| --- | --- | --- |
| id | string |  |
| version | integer |  |
| created_at | string |  |
| updated_at | string |  |

Response example — HTTP 201

| Header | Value |
| --- | --- |
| content-range | 0-0/* |
| preference-applied | resolution=merge-duplicates, return=representation |
| range-unit | items |

```json
[
  {
    "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-rows]

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

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

### Response [#response-5]

#### HTTP 200 [#http-200-3]

Success; write bodies require Prefer: return=representation

**application/json**

| Name | Type | Description |
| --- | --- | --- |
| [].id | string |  |
| [].version | integer |  |
| [].created_at | string |  |
| [].updated_at | string |  |

**application/vnd.pgrst.object+json**

| Name | Type | Description |
| --- | --- | --- |
| id | string |  |
| version | integer |  |
| created_at | string |  |
| updated_at | string |  |

#### HTTP 204 [#http-204-1]

Success without a body

No response body is declared.

Response example — HTTP 200

| Header | Value |
| --- | --- |
| content-range | 0-0/* |
| preference-applied | return=representation |
| range-unit | items |

```json
[
  {
    "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
  }
]
```
