telnyx-edge CLI. Remote commands reach a deployed database
through the same primary as the env binding, so remote CLI SQL and SQL run from a deployed
function are serialized together. Local commands use an isolated Docker-backed database and do
not read or change deployed data.
The
storage sqldb family requires CLI v0.3.0 or newer — the first release to carry any SQL
surface. export requires CLI v0.5.0 or newer. 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:
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:
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. For --remote, execute and the migrations subcommands
accept either the id or the database name — see Addressing a Database. In --local mode, the argument is the local database name (or a manifest binding name) and does not trigger an organization lookup.Running SQL
execute runs SQL against a database without deploying anything — to create a schema, load
seed data, or inspect what a function wrote.
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 still means a SQL hex literal (X'090807'): --param carries strings, numbers, booleans
and null, and JSON has no byte-array form to bind. From a function, bind an ArrayBuffer instead.
Binding Values
Pass values with--param instead of writing them into the SQL. Both flags are repeatable and
fill the statement’s ? placeholders left to right, in the order they appear on the command line:
--param always sends a string; --param-json parses its argument as one JSON value, which is
the only way to bind a number, boolean, or null from a shell — --param 42 binds the text "42",
--param-json 42 binds the integer. The count must equal the number of placeholders, or the call
is rejected with a 422 naming both counts. Neither flag combines with --file: a script binds to
its last statement only, so the CLI refuses rather than binding somewhere you did not choose.
Bind anything that came from outside your own script — that is what keeps a quote or a -- in the
data from changing the statement.
execute Flags
Choose exactly one target:
--remote for a deployed SQLDB or --local for an isolated database on your machine. Local mode uses the runtime SQL engine in Docker.;-separated statements; all of them run in order, and the rows returned are the
last statement’s rows. For --remote, the whole script must fit under the ~4 MiB request ceiling
(see Limits). This request-size ceiling does not apply to --local --file.
A database that has not finished provisioning rejects execute with
409 — Database is not ready (status: pending). Wait for provision_ok.
Local SQLDB development
Local SQLDB support is available in CLI v0.5.12 and newer. It requires Docker and the actor-runtime image used by
telnyx-edge dev. Local databases are separate from deployed SQLDBs: running a local command never changes production data.--local instead of --remote to execute SQL or list and apply migrations on your machine:
.telnyx/sqldb/ in the project directory and is excluded from Git. Delete that directory to reset local databases. Use --persist-to <directory> to store CLI local databases elsewhere; telnyx-edge dev only shares the default location.
If telnyx.toml declares [storage.sqldb.DB], pass DB to local commands to use the same database as env.DB when running telnyx-edge dev. You do not need to provision a remote SQLDB to develop locally.
--remote and --local are mutually exclusive; one is required for execute, migrations list, and migrations apply. Local commands run a short-lived Docker container and do not require a running dev stack.
Export
export dumps a database as a .sql file — schema, data, or both. Exports can be up to 4 GiB (CLI v0.5.15+). For restoring dumps larger than the approximately 4 MiB execute --remote --file request limit, use storage sqldb import (CLI v0.5.16+, up to 100 MiB).
CREATE statements followed by INSERT statements, then indexes,
views, and triggers. Values keep their exact storage class, including integers too large
for a JSON number and BLOBs.
The export runs as a job: the CLI queues it, polls until the dump is ready, then streams
it to the file you named. The file is written to a temporary file in the destination
directory and renamed into place on completion, so a failure never leaves a partial file
wearing the final name. Files are created with mode 0600 — a dump is every row in
plaintext.
Databases containing virtual tables (for example FTS5) cannot be exported, because their
contents live in shadow tables that do not round-trip. The export is not a point-in-time
snapshot: a write committed while it runs may be partially reflected.
export Flags
--no-data and --no-schema cannot be combined (together they would export nothing).
Large SQLDB exports
As of CLI v0.5.15,storage sqldb export supports dumps up to 4 GiB. The existing --remote --output syntax is unchanged. Exports are produced through Cloud Storage rather than held entirely in memory.
The execute --remote --file command still has an approximately 4 MiB SQL script limit. For larger restores, use the dedicated import command below. Note that the import ceiling is 100 MiB, lower than the 4 GiB export ceiling: not every export can be imported through the CLI.
Import SQL dumps
Available in telnyx-edge v0.5.16 and newer. Imports support SQL dump files up to 100 MiB.
storage sqldb import to restore a SQL dump through Telnyx Cloud Storage instead of sending the whole file through execute --remote --file:
--from-export. An import into a nonempty database asks for confirmation; pass --yes to skip the prompt. This does not bypass the 100 MiB size limit.
Validation and partial failures: The complete SQL dump is validated before application. The import then runs in batches. Each batch is atomic, but the overall import is not atomic: if a later batch fails, successfully applied earlier batches remain in the database. Review the detailed error and current database contents before retrying.
Progress and cancellation: The CLI shows import progress. Pressing Ctrl-C stops the CLI from waiting, not the server-side import. Use the printed import status command to resume checking. The CLI also supports --json output for completed imports.
Cloud Storage cleanup: For --file imports, the temporary uploaded object is removed on success. On failure it is retained and the CLI prints its bucket and key. Imports using --from-export do not delete the original export.
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.
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
For--remote, execute, migrations list, and migrations apply resolve the
<database> argument against deployed SQLDBs:
- 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 "...".
--local, there is no organization lookup. A manifest binding name or that binding’s
database ID opens the same local database used by telnyx-edge dev. Any other name creates or
opens its own local-only database under the local persistence directory.
Names are unique within an organization, so an ambiguous remote match should not occur in practice —
the CLI guards against it anyway. get and delete do not resolve names; they take the id.
Related
- Quick Start — create a database, bind it, query it
- Migrations — versioned schema changes and the
sqldb_migrationsledger - Limits — request body size, query duration, and what is not enforced
SqlDatabase— theenvbinding surface- CLI Reference — every
telnyx-edgecommand