# SQL support and limits

> Resta databases use the SQLite dialect. Some statements are blocked for safety, and each database has size and time limits.

Source: https://resta.dev/docs/sql · Updated 2026-11-01

**Resta databases speak the SQLite dialect and store data in the SQLite file format; a few statements that could reach outside the database file are blocked, and every request runs under size and time limits.** Most SQLite SQL works unchanged: tables, indexes, views, triggers, CTEs, JSON functions, `generate_series`, transactions and savepoints.

## Engine

Resta runs [Turso](https://github.com/tursodatabase/turso) 0.8, an SQLite-compatible engine written in Rust. Turso tracks SQLite 3.50 and is not yet 100% compatible; its [compatibility list](https://github.com/tursodatabase/turso/blob/main/COMPAT.md) shows what is missing. Database files are SQLite files: a snapshot opens in the `sqlite3` command-line tool.

## Blocked statements

These return the error code `BLOCKED`, because they could read or write files on the server other than the database's own:

| Statement | Why |
|---|---|
| `ATTACH`, `DETACH` | Would open another file. |
| `VACUUM`, `VACUUM INTO` | `VACUUM INTO` writes to any path. Snapshots use it internally. |
| `CREATE VIRTUAL TABLE` | No modules are offered. |
| `CREATE TEMP TABLE / VIEW / TRIGGER` | Temp objects live in server memory, outside the size limit. |
| `load_extension()`, `sqlite_dbpage` | Native code and raw pages. |
| Most `PRAGMA`s | Only those that touch the database's own data or session are allowed. |

Allowed pragmas: `application_id`, `defer_foreign_keys`, `encoding`, `foreign_key_check`, `foreign_key_list`, `foreign_keys`, `freelist_count`, `function_list`, `ignore_check_constraints`, `index_info`, `index_list`, `index_xinfo`, `integrity_check`, `page_count`, `page_size`, `quick_check`, `recursive_triggers`, `schema_version` (read), `table_info`, `table_list`, `table_xinfo`, `user_version`. Of these, only `application_id`, `defer_foreign_keys`, `foreign_keys`, `ignore_check_constraints`, `recursive_triggers` and `user_version` can be set.

## Limits

| Limit | Default | What happens |
|---|---|---|
| Database size | 1 GiB | Writes past it fail with `SQLITE_FULL`. |
| Statement time | 5 s | The statement fails with `SQLITE_INTERRUPT`. |
| Request time | 30 s | The request fails with `408`. |
| Request body | 10 MiB | `413`. |
| Response size (pipeline) | 10 MiB | `RESPONSE_TOO_LARGE`; use `LIMIT` or the cursor endpoint, which streams. |
| Statements per pipeline, steps per batch | 1,000 each | `400`. |
| Concurrent requests per server | 256 | `503`; retry with backoff. |

The defaults can be changed: see [Configuration](https://resta.dev/docs/configuration#limits).

## Writers

Each database allows one writer at a time, as in SQLite. Writes to the same database queue; writes to different databases run in parallel. This is one reason to split data into many databases.

## Error codes

SQL errors use SQLite's codes: `SQLITE_CONSTRAINT` (with `extended_code` such as `SQLITE_CONSTRAINT_UNIQUE`), `SQLITE_ERROR`, `SQLITE_BUSY`, `SQLITE_FULL`, `SQLITE_INTERRUPT`, plus `SQL_PARSE_ERROR`, `SQL_INPUT_ERROR` (wrong argument count), `SQL_MANY_STATEMENTS`, and `BLOCKED`.
