Skip to main content
Manage SQL databases using the telnyx-edge CLI. Every command in this family reaches a database through the same primary as the env binding, so the CLI is not a second writer — SQL run from a terminal and SQL run from a deployed function are serialized together.
The storage sqldb family requires CLI v0.3.0 or newer — the first release to carry any SQL surface. On v0.2.5 and earlier telnyx-edge storage sqldb fails as an unknown command. Check with telnyx-edge --version.

Database Management

create returns immediately with status: pending; provisioning finishes in the background, typically in 2 to 11 seconds:
Poll get until the status is provision_ok:
list paginates, newest first:
delete takes effect immediately and asks nothing first — there is no confirmation prompt and no --yes flag:
The record disappears shortly afterwards: get and any query against that id return 404. Delete removes the database record and makes the data unreachable through every path; it is not a guaranteed erase of the stored bytes, so it does not satisfy a data-destruction requirement on its own. It also does not touch functions that still declare the id in a [storage.sqldb.<NAME>] block: those functions stay deployed and their queries start failing. Remove the block and redeploy them.

list Flags

get and delete take the database id only. execute and the migrations subcommands accept either the id or the database name — see Addressing a Database.

Running SQL

execute runs SQL against a database without deploying anything — to create a schema, load seed data, or inspect what a function wrote.
A statement that returns no rows prints a confirmation:
A read prints a table and a row count:
Columns are ordered alphabetically rather than by their order in the SELECT list, and a SQL NULL renders as NULL. To learn a new row’s id, or to count the rows a write touched, add RETURNING to the statement and count the rows it prints. SELECT changes() in a separate call reads a counter on a connection shared with every other caller of the database, so another write can land in between. --json prints the raw result object instead of a table — on stderr in the current CLI, so scripts should capture it with 2>&1 >/dev/null rather than piping stdout. results holds the rows and is the only field the service returns — a statement that produces no rows prints {}:
BLOB columns cross this boundary as a JSON array of byte values — a three-byte blob comes back as [9, 8, 7], not base64 and not an object. Decode it as bytes on the client. Writing binary this way means a SQL hex literal (X'090807'), since this path has no parameter binding; from a function, bind an ArrayBuffer instead.

execute Flags

--remote is mandatory. Omitting it fails with --remote is required before any network call: there is no local SQLite emulation to run against, and no --local flag.
The SQL text is submitted verbatim — the CLI never splits statements itself. A script may hold several ;-separated statements; all of them run in order, and the rows returned are the last statement’s rows. The whole script must fit under the ~4 MiB script ceiling (see Limits). A database that has not finished provisioning rejects execute with 409Database is not ready (status: pending). Wait for provision_ok.

Migrations

Versioned schema changes live in numbered .sql files and are tracked in a sqldb_migrations table inside the database itself.

migrations Flags

The full workflow — file naming, the ledger table, and what happens when a migration fails midway — is covered in Migrations.

Generating Types

telnyx-edge types reads the manifest and writes telnyx-env.d.ts, so env.<BINDING> is typed at compile time. It runs fully offline — no authentication, no network.
Two things are checked before anything is written: the id must be a well-formed UUID (inline creation and binding by name are rejected), and @telnyx/edge-runtime in package.json must be 0.9.0 or newer — the first version that exports SqlDatabase. An older pin fails with @telnyx/edge-runtime <declared version> does not export SqlDatabase (requires >= 0.9.0), quoting the range exactly as package.json declares it.

Addressing a Database

execute, migrations list, and migrations apply take a <database> argument that resolves either way:
  • An exact id match always wins.
  • A name resolves when exactly one database in the organization carries it.
  • A name shared by several databases errors with Multiple SQL databases are named "..." — pass the id instead.
  • No match errors with No SQL database found matching "...".
Names are unique within an organization, so an ambiguous match should not occur in practice — the CLI guards against it anyway. get and delete do not resolve names; they take the id.
  • Quick Start — create a database, bind it, query it
  • Migrations — versioned schema changes and the sqldb_migrations ledger
  • Limits — request body size, query duration, and what is not enforced
  • SqlDatabase — the env binding surface
  • CLI Reference — every telnyx-edge command