Deploying

zsql deploy packs the project directory into a tar.gz, POSTs it to the service under the checked-out git branch, and prints what the service loaded: counts, warnings and test results. zsql check does the same against the validate route and keeps nothing.

zsql check

zsql check

Identical to zsql deploy --dry-run: the same archive, the same loader, the same output with validate/validated in place of deploy/deployed. Nothing is stored. See Modeling with zsql for a transcript.

zsql deploy

zsql deploy [--dry-run] [--watch]
$ git branch --show-current
main
$ zsql deploy
deploy tpcds (6214 bytes) as tpcds/main (the production branch) to https://app.0sql.io
deployed tpcds/main: 6 tables, 42 fields, 5 joins, 9 paths, 1 policies
PASSED store net paid by category
PASSED catalog quantity by month
PASSED date range
tests: 3 passed, 0 failed

The first line says what is being sent and where: the project name, the archive size, the uid/branch it lands on, and (the production branch) when the branch equals production_branch in project.yml. The second line is the service’s summary. Then one warning: line per warning, one line per test, and the test total. A project with no tests/*.yml prints no tests deployed (tests/*.yml) instead.

What goes in the archive

ShippedNever shipped
project.yml.zsql, .strata
security.yml.git
datasources.yml with secret keys removed (password, private_key, personal_access_token, secret_access_key, access_key_id, oauth_client_secret, oauth_client_id, api_key)data files, anything not listed on the left
every .yml / .yaml under models/ and tests/

Exit codes

zsql deploy exits non-zero when the service rejects the archive (a DeployError naming the file and message) and when any test fails. Note the second case: the HTTP deploy succeeds with status 200 and the branch is live with the new model, but the CLI prints tests failed and exits non-zero so a CI job stops. Check the output, fix the model or the test, deploy again.

$ zsql deploy
deploy tpcds (6240 bytes) as tpcds/main (the production branch) to https://app.0sql.io
deployed tpcds/main: 6 tables, 42 fields, 5 joins, 9 paths, 1 policies
PASSED store net paid by category
FAILED catalog quantity by month
       --- generated
       SELECT
       	DATE_TRUNC('month', T1."d_date")::DATE AS "Month(Date)",
       	sum(T0."cs_quantity") AS "Catalog Quantity"
       FROM
       	catalog_sales T0
       	JOIN date_dim T1
       		ON T0.cs_sold_date_sk = T1.d_date_sk
       GROUP BY
       	DATE_TRUNC('month', T1."d_date")::DATE
PASSED date range
tests: 2 passed, 1 failed
Error: tests failed
$ echo $?
1

The production branch

Deploying while main (or whatever production_branch names) is checked out updates what production reads. The output says so: as tpcds/main (the production branch). On the service a project owner can mark the production branch protected; then deploying to it needs owner access, and anyone else gets Forbidden: deploying to the protected production branch 'main' of tpcds needs an owner.

—watch

$ zsql deploy --watch
deploy tpcds (6214 bytes) as tpcds/main (the production branch) to https://app.0sql.io
deployed tpcds/main: 6 tables, 42 fields, 5 joins, 9 paths, 1 policies
tests: 3 passed, 0 failed
watching /home/you/tpcds for changes (ctrl-c to stop)

Deploys once, then polls the project directory every 500 ms for a changed .yml or .yaml file and redeploys 200 ms after a change. Errors are printed and watching continues. Pair it with the repl in a second terminal to edit a model and query it as you go.

Branches

The service branch is the checked-out git branch. There is no separate “promote” step: a branch is deployed by checking it out and running zsql deploy, and main is updated by merging and deploying main.

  • zsql deploy on feature/returns creates or updates tpcds/feature/returns. Nothing else changes.
  • Each deployed branch is a complete, isolated model. An application names the branch it wants in the URL: /projects/tpcds/branches/feature/returns/sql.
  • A query key granted a project without a branch reads production_branch. A key granted * reads every branch; a key granted one branch name reads that one.
  • --branch NAME overrides the git branch. CI checkouts are often detached, so pass it there (see CI/CD).

Deploying from a dirty working tree deploys the files on disk, committed or not.

zsql status

The deployed branch’s summary, as the service returns it.

$ zsql status
{
  "project": "tpcds",
  "branch": "main",
  "deployed_at": "2026-10-01 15:04",
  "datasources": 1,
  "tables": 6,
  "fields": 42,
  "joins": 5,
  "paths": 9,
  "policies": 1,
  "tests": 3,
  "warnings": []
}

A branch that was never deployed answers NotFound: no deployment for project tpcds branch feature/returns.

zsql list

One line per deployment the key can see, across projects and branches.

$ zsql list
tpcds                            main             6 tables, 42 fields, 1 policies, 3 tests
tpcds                            feature/returns  7 tables, 48 fields, 1 policies, 3 tests

zsql list works outside a project directory too; it only needs a key and a server.

zsql remove

Removes the deployed branch from the service. The confirmation is a flag.

$ zsql remove
Error: this removes tpcds/feature/returns from https://app.0sql.io; add --yes to confirm
$ zsql remove --yes
{
  "removed": "tpcds/feature/returns"
}

Removing a branch removes its deployment, not the project or the git branch.

zsql test

Runs the tests the branch was deployed with, on the service, without redeploying. Useful after a key or policy change, and as a cheap health check of a branch.

$ zsql test
PASSED store net paid by category
PASSED catalog quantity by month
PASSED date range
tests: 3 passed, 0 failed

Exits non-zero with tests failed when any fail. The format is on Tests.

Next steps