Limits and errors

Capacity, query limits and error handling.

Plan databases and queries within these limits.

LimitMaximum
Tables per database50
Fields per table64
Indexed fields per table (including unique)16
Rows per table1000000
Bytes per row2097152 (2 MiB)
Rows per insert500
Parameter values per query100
Database recovery window, days7
Rows scanned per query3000000

Each request may run for up to 8 seconds; a timeout returns 57014 and retrying will not help. Index the fields you filter and sort on, or narrow the query. Counting without a filter is always fast. Without a limit a read returns at most 1000 rows; page with limit / offset or Range. To update or delete many rows in a large table, work in batches over primary-key or indexed ranges, for example tens of thousands of rows per batch. Batch inserts support the row limit above; do not multiply rows by fields to estimate query parameters.

Error codes and retryability → One batch POST inserts at most 500 rows. Each request is atomic: a failure in any row rolls back the entire batch. There are no transactions across requests. Put rows that must succeed together in one batch POST. For links, query first, then insert, and handle link errors caused by concurrent changes.

Rows in a batch are filled to the union of their keys with null (PostgREST behavior). Send Prefer: missing=default to use field defaults instead. Explicit null remains null; required fields without defaults must still be provided. The default return=minimal returns 201 with an empty body; send Prefer: return=representation to return rows.

Correct the request using error details

Only id is a reserved field name. New field names cannot start with _, which is reserved for system metadata. created_at, updated_at and version are ordinary user field names. Datetime fields can use "now()" as a default.

details identifies the field or JSON path and the received value. Batch validation includes a zero-based row index. Values are limited to 80 characters; the entire row is never echoed. hint suggests a correction, or is null when no suggestion applies. This example omits the required title in row 2:

{
  "code": "23514",
  "message": "row validation failed",
  "details": "row 1: title: required value (got null)",
  "hint": "Rows in one insert are filled to the union of their keys with null (PostgREST behavior). Send every key in every row, or send Prefer: missing=default to use field defaults."
}

A unique conflict returns 409, for example:

{
  "code": "23505",
  "message": "unique constraint violated",
  "details": "Key (email)=(a@b.c) already exists.",
  "hint": null
}
Export

On this page