Skip to main content
A release is a stored, named record of a backend that came up and answered on Xano’s cloud. It holds an archive of that backend, so it outlives the environment it was cut from, and promote v1.4.0 a week later lands exactly what was tested. promote and tenant deploy take nothing else. Every release is stored in your workspace, whatever it was cut from. release list, promote and tenant deploy all read it there.

Cut a release

Deploy to an ephemeral and run the tests, then cut the release from what is running there:
--test exits 5 if a test fails and 6 if the tests cannot be reached. The deploy stays in place either way, so check the exit code before you cut. With no --from, release create cuts from the backend this project last deployed to. If you deployed to the Xano Engine since, name the ephemeral: release create v1.4.0 --from ephemeral. A release cannot be cut from the Engine; see where the Engine differs today. Cutting reads the source and writes nothing to it, so the ephemeral expiring later takes nothing with it. The cut also compares the source against a compile of your project and names every object that differs. The release carries what is running, not what is on your disk, so read that list before you promote.

Choose the source

To start from what a live tenant runs, pull it into the project, deploy that to an ephemeral, and cut from there:

When ephemerals are off: stage on a Xano branch

Some instances have ephemerals turned off, and deploy --ephemeral says so. There, stage the build on a new Xano branch of your workspace and cut the release from that branch:
deploy --to workspace --branch creates the Xano branch as a copy of live and lands your build there. The live Xano branch keeps serving. Know three things about this path:
  • The label must be new. A label that already exists is refused (SDK_BRANCH_TAKEN, exit 2). Delete the staging Xano branch after you cut, or use one label per release (staging-v1.4.0).
  • Table changes reach live at this step, not at promote, because every Xano branch shares the same tables. The deploy refuses a table change (SDK_SHARED_SCHEMA_CHANGE) until you pass --allow-shared-schema-changes. See Where code goes.
  • --test is not available beside --to. Run your tests on the Engine before you stage.
  • The release carries everything that branch runs, not only your project: the Xano branch starts as a copy of live, so objects live already serves ride along. release create lists what differs from your project before it cuts.

What a release carries

Every table’s schema, always. A release cut with no flags has every table in it. Table rows only when you ask. List the source’s tables with their guids, then pass the guids of the tables whose rows should ride along:
List from the backend you are cutting from: a guid read off another backend is not proof of the same table. Selection is by guid because a guid that does not match is refused before anything is cut, where a stale id would silently select a different table. When a selected table has a non-public column, the cut names it and asks first (--yes answers in advance). Two things a release never carries:
  • File bytes. A file column’s value and an MCP icon declared with hostedFile() point into the source’s file library, and the release would copy the pointer without the file. So release create refuses a cut whose source serves hostedFile() icons, or whose --seed selects a table with a file column while the source holds files (SDK_RELEASE_FILES_NOT_CARRIED, exit 2). Land a project like that with a direct deploy, which ships its files: npx xanosdk deploy ./xano/index.ts --to tenant:prod --seed. See Tenants.
  • Env values. A landing adds names the target lacks and never overwrites a value it holds. See Env and secrets.
Seeded password columns carry hashes, and each environment hashes with its own key. Logins against those rows work only on the environment the release was cut from.

Name a release

A name is used once. A name that is taken is refused (SDK_RELEASE_NAME_TAKEN, exit 2), because a tenant may be running the release that holds it. Cut a new name, such as v1.4.1. After exit 9, read before you retry. Exit 9 means the cut was sent and the answer was lost (a timeout, a dropped connection, a server error). The release may exist. The platform stores a write under a taken name with a dash and four hex characters added (v1.4.0-a019) rather than refusing it, so a blind retry can leave two releases. List first:
Look for v1.4.0, or v1.4.0- plus four hex characters, created after the run started. If the server stored your cut under a suffixed name, release create refuses rather than reporting success, and prints the release delete that removes the stray copy. The run’s --json document names the read to run (resolveWith) and the earliest time an “absent” answer is proof (resolveNotBefore). Exit codes and outcomes covers every code.

Manage releases

To bring a release’s code back into your project, use npx xanosdk pull release:v1.4.0.

Next

Promote and go live: land the release on your workspace and serve it.