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

# Rollback and recovery

> Go back to the previous release on your workspace with workspace branch set-live or on a tenant with tenant deploy, restore logic after a merge with --backup-branch, roll back the frontend, and recover a tenant deploy that stopped partway or a release write whose outcome is unknown (exit 9).

There is no rollback command. Production always runs a release, so going back means serving the
previous one again, with the commands below. Each of them restores **logic**. None of them
restores a table change or the rows it destroyed.

| You shipped with | Go back with |
| - | - |
| `promote` to your workspace | `xanosdk workspace branch set-live <previous label>` |
| `tenant deploy` to a tenant | `xanosdk tenant deploy <tenant> <previous release>` |
| `deploy --to workspace --backup-branch` | `xanosdk workspace branch set-live <backup label>` |
| `publish` of a frontend | `publish` of the previous build, with `--release` and `--branch` |

## On your workspace: switch live back

A promote lands on a new Xano branch and leaves the previous one in place, so going back is
switching live to it. Every switch prints the exact command that undoes it, whether it came from
`promote --set-live` or `workspace branch set-live`:

```
  on your-instance.xano.io · workspace 3

! This is a production cutover for workspace #3.
  The runtime stops serving "v1.3.2" and starts serving "v1.4.0".
  Table data is unaffected — it is shared by every branch either way.

✓ Branch "v1.4.0" is now live in workspace #3.
  Roll back with `npx xanosdk workspace branch set-live v1.3.2 --yes`.
```

Under `--json` the same label is `previousLive`. If you no longer have the output, list the Xano
branches; the one you promoted before is still there:

```bash theme={null}
npx xanosdk workspace branch list
npx xanosdk workspace branch set-live v1.3.2 --expect-live v1.4.0
```

`--expect-live v1.4.0` refuses unless `v1.4.0` is live, checked before asking and again
immediately before switching, so a rollback never undoes someone else's newer release by
accident. A check that fails exits `2` with `SDK_LIVE_BRANCH_MISMATCH`. Off a terminal, add
`--yes`.

Keep the previous release's Xano branch until the new one has served for a while. Once you
delete it with `workspace branch delete`, the way back is promoting the previous release again.

## On a tenant: deploy the previous release

A tenant serves exactly one release, so going back is deploying the release it ran before:

```bash theme={null}
npx xanosdk tenant get prod            # which release prod last landed
npx xanosdk tenant deploy prod v1.3.2
```

It is a replace like any other tenant deploy. A table the newer release added is dropped with its
rows, a column it added loses its values, and values a conversion rewrote are not converted
back. The confirmation names each of these before you answer; read it.

## After a merge: the backup Xano branch

A merge into the live Xano branch (`deploy --to workspace`) leaves no release to go back to.
Take a snapshot first with `--backup-branch`, and the way back is switching live to it:

```bash theme={null}
npx xanosdk deploy ./xano/index.ts --to workspace --backup-branch=before-orders-api
npx xanosdk workspace branch set-live before-orders-api     # if the merge has to come out
```

With no label, `--backup-branch` derives one and prints it. The snapshot holds the live Xano
branch's logic only; a column the merge dropped stays dropped after the switch back.

## Table changes are never rolled back

Tables are shared by every Xano branch, so a table change reaches live when a release lands and
stays when you switch live back. On a tenant, deploying the previous release changes the tables
again rather than restoring them. In both cases a dropped column or table comes back empty, if
it comes back at all.

* Change a column across two releases (expand, backfill, contract), so every release can be
  rolled back to the one before it. See [Schema changes](/govern/schema-changes).
* Back up the workspace or tenant in the Xano dashboard before a release that drops or rewrites
  a column. A backup is how you recover the rows.
* Preview with `deploy --to … --dry-run` and read `droppedColumns` before you ship.

## Roll back the frontend

A frontend is published separately from the backend, and neither a promote nor a rollback
touches the static host. After you switch live back, publish the build that belongs to the
previous release, built from its git tag:

```bash theme={null}
git switch --detach v1.3.2
npm ci && npm run build
npx xanosdk publish ./frontend/dist --to workspace --release v1.3.2 --branch v1.3.2 --yes
```

`--release` checks that the release exists and reports it with the publish. `--branch` refuses
unless `v1.3.2` is the live Xano branch, so the frontend cannot land in front of a backend it was
not built for. On a tenant, publish the same build with `--to tenant:prod`.

## Recover a tenant deploy that stopped partway

A tenant deploy can stop partway when the tenant's rows break something the release adds: a
unique index over rows that share a value, a required field that rows leave empty, or a stored
value a retype cannot convert. The tenant may then serve part of each release.

The run fails with `completed: "no"`, `partlyReplaced: true`, the `constraint` it hit, and
`recoverWith`, the `tenant deploy` of the release the tenant ran before. Run it:

```bash theme={null}
npx xanosdk tenant deploy prod v1.3.2 --yes     # the recoverWith command from the failed run
```

That puts the previous release's logic and definitions back. Values a conversion already
rewrote stay rewritten. Fix the rows the `constraint` names, then deploy the new release again.

## Recover a release write whose outcome is unknown (exit 9)

Exit `9` means a `release create`, `promote`, `tenant deploy` or `release transfer` sent its
write and lost the answer: a timeout, a dropped connection, a server error, or Ctrl-C mid-write.
The write may have happened. **Read before you retry**, never retry blind.

The run's document (`--json`, or stdout whenever it is not a terminal) carries what to read:

| Field | What it is |
| - | - |
| `resolveWith` | The command that answers whether the write happened. Run it first. |
| `resolveSteps` | What to do with each answer it gives. |
| `resolveNotBefore` | The earliest time an "absent" answer is proof. Before then, the server may still be finishing the write. |

What to check for each command:

* **`release create`.** Run `xanosdk release list` and look for the name, or the name with a
  dash and four hex characters (`v1.4.0-a019`). The platform stores a write under a taken name
  with that suffix instead of refusing it, so a blind retry can leave two releases. If the cut is
  stored under a suffixed name, delete the stray copy with `xanosdk release delete` and keep one.
* **`promote`.** Run `xanosdk workspace branch list --json`. If the label is there, the release
  landed. If it is absent after `resolveNotBefore`, nothing landed: re-run with the same
  `--branch` and `--yes`. A bare re-run lands a second Xano branch.
* **`tenant deploy`.** Run `xanosdk tenant get prod --json` and compare `deployedAt` with its
  value before the run. A `deployedAt` that moved means the release landed. One that did not move
  can also mean a deploy that stopped partway, so deploy the previous release again to be sure.
* **`release transfer`.** Run the same transfer with `--dry-run`. It reports whether the copy is
  at the destination.

[Exit codes and outcomes](/help/exit-codes-and-outcomes) lists every code.

## Next

[CI/CD](/govern/ci-cd): run the release flow, and these checks, from your pipeline.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.