> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Limits

> Limits for Telnyx SQL databases: 1 GiB per database, 2 MiB per bound value, 32,766 bound parameters, a ~4 MiB SQL script and result-set ceiling, and name rules.

## Limits

| Limit                          | Value                                | Behavior past it                                                                                                           |
| ------------------------------ | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
| Database size                  | 1 GiB                                | Writes fail the way SQLite fails on a full disk                                                                            |
| One bound value                | 2 MiB                                | `SqlParameterTooLargeError`, before the statement runs                                                                     |
| Bound parameters per statement | 32,766                               | SQLite's variable limit                                                                                                    |
| SQL script, REST and CLI       | \~4 MiB                              | `422` — the transport rejects the request with `stream too large`; past 8 MiB, `413` — `SQL body exceeds the maximum size` |
| Rows returned by one statement | \~4 MiB                              | The query fails with a `ResourceExhausted … larger than max` error — on the REST path and the `env` binding alike          |
| Expression tree depth          | 1,000                                | `Expression tree is too large`                                                                                             |
| Database name                  | `^[a-z0-9-]+$`, up to 255 characters | Character-set violations return `422`; past 255 characters the create fails with `500`; a duplicate name returns `409`     |

**The \~4 MiB script ceiling** covers the whole SQL script sent over the REST query path — which
is also what `telnyx-edge storage sqldb execute --file` and `migrations apply` use. The service
advertises an 8 MiB gate and returns the `413` past it, but the transport underneath rejects
anything over roughly 4 MiB (4,194,304 bytes, less a few hundred bytes of envelope) with a `422`
whose detail ends in `stream too large` — so \~4 MiB is the number to plan against, and a large
seed file needs splitting across several calls.

**Result sets are capped at the same \~4 MiB, per statement.** A query whose rows exceed it fails
with a `ResourceExhausted … trying to send message larger than max` error, through REST and
through the `env` binding alike. Only shipping the rows is capped — computing over the same data
server-side (`length()`, aggregates) is fine — so page through large reads instead of selecting
them whole.

**The 2 MiB cap applies only to values passed through `.bind()`.** A value produced inside SQL
is never bound and never checked, which is why `randomblob(100000000)` stores without
complaint. Keep anything approaching either figure — images, archives, model weights — in
[object storage](/docs/cloud-storage/bindings) and bind the key instead.

Database size and bound-value size come from the SQLite storage engine that SQL Databases share
with [per-actor SQLite](/docs/edge-compute/stateful-actors/guides/storage/sql), so the same
numbers apply on both surfaces.

## Query Performance

A database is served by one primary, and statements run one at a time. A long statement delays
everything else queued against that database, so the useful discipline is keeping individual
statements short.

| Query                  | Typical            |
| ---------------------- | ------------------ |
| Simple statement, warm | \~10 ms round trip |
| 5,000-row read         | \~160 ms           |

Add indexes on the columns you filter and order by, page through large result sets instead of
selecting them whole, and maintain a summary table on write rather than aggregating across
millions of rows on read. Long analytical scans belong in a warehouse, not here.

```sql theme={null}
CREATE INDEX IF NOT EXISTS links_by_slug ON links(slug);
```

## Related

* [`SqlDatabase`](/docs/edge-compute/sqldb/reference/sql-database) — the binding surface: methods, type conversion, and errors
* [How SQL Databases Work](/docs/edge-compute/sqldb/concepts/how-sqldb-works) — one primary per database
* [Migrations](/docs/edge-compute/sqldb/migrations) — versioned schema changes
* [CLI](/docs/edge-compute/sqldb/cli) — `execute`, `migrations`, and database management
* [Stateful Actor SQL](/docs/edge-compute/stateful-actors/guides/storage/sql) — the separate per-actor SQLite database
* [Edge Compute Limits](/docs/edge-compute/platform/limits) — function request timeout, memory, and body sizes
