> ## 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.

# Schema changes

> Change a table safely when every Xano branch shares the same tables: what lands without a flag, what promote refuses until you pass --allow-shared-schema-changes, and how to rename or drop a column across two releases with expand, backfill and contract.

A Xano branch holds logic. **Tables are shared by every Xano branch** in a workspace, so a
table change reaches live the moment a release lands, before any `--set-live`, and deleting the
Xano branch it landed on does not undo it. Switching live back to an earlier Xano branch restores
logic, never a dropped column or its values.

Plan every table change as a change to production data.

## What lands, and what is refused

`promote` compares the release's tables with your workspace before it lands anything:

| Change in the release | `promote` |
| - | - |
| A new table | Named, and lands. |
| A new column | Named, and lands. |
| A non-unique index added or dropped | Lands. It changes how rows are found, not what they hold. |
| A column dropped, retyped, or made required | Refused until `--allow-shared-schema-changes`. |
| A unique index added | Refused until `--allow-shared-schema-changes`. Rows that break it refuse the landing anyway (`SDK_CONSTRAINT_VIOLATION`). |

A refusal exits `2` with `SDK_SHARED_SCHEMA_CHANGE` and lists every change, additions included,
under `details.changes`. `--yes` does not waive it.

```bash theme={null}
npx xanosdk promote v1.4.0 --branch v1.4.0                                  # refused: the release alters a table
npx xanosdk promote v1.4.0 --branch v1.4.0 --allow-shared-schema-changes    # you accept that live changes now
```

`deploy --to workspace --branch <label>` refuses the same way, because a Xano branch stages
logic and not schema. A plain `deploy --to workspace` onto the live Xano branch previews the
change instead: it names each column it would drop and asks before it sends anything.

On a tenant there are no Xano branches, and a `tenant deploy` replaces what the tenant serves:

* **A table the release does not carry is dropped with every row.** The confirmation names
  each one with its row count.
* **A dropped column loses its values. A retyped column's values are converted** (`"1.5"`
  becomes `2`), and a column made required has its nulls rewritten to the type's empty value.

`--yes` skips that confirmation. In CI nobody reads it, so review the change before the tag.

## See the change before it lands

`promote` and `tenant deploy` run no local plan. The merge path does, and `--dry-run` sends
nothing:

```bash theme={null}
npx xanosdk deploy ./xano/index.ts --to workspace --dry-run     # against the live Xano branch
npx xanosdk deploy ./xano/index.ts --to tenant:prod --dry-run   # against a tenant
```

Read `droppedColumns` in the plan (`--json` carries it). Every column listed there loses its
values when the release lands.

## Rename or drop a column across two releases

A column dropped beside a column added is not a rename. Columns have no rename identity, so the
old values are destroyed and the new column starts empty. `promote` calls the pair out under
`details.pairedColumns`.

To keep the data, spread the change over two releases: **expand**, **backfill**, **contract**.
Say `users.name` becomes `users.display_name`:

<Steps>
  <Step title="Expand: add the new column (release v1.4.0)">
    Add `display_name` beside `name`. Write both columns, and read `display_name`, falling back
    to `name` while it is empty:

    ```ts theme={null}
    schema: {
      name: f.text(),          // still here: old rows hold their values
      display_name: f.text(),  // new
    },
    ```

    A new column is an addition, so `promote v1.4.0` lands it without the flag, and a tenant
    deploy keeps every existing value.
  </Step>

  <Step title="Backfill: copy the values">
    With v1.4.0 serving, copy `name` into `display_name` for every row where `display_name` is
    empty, for example with a one-off [task](/build/tasks). Check the count of
    rows still empty is zero before you go on.
  </Step>

  <Step title="Contract: drop the old column (release v1.5.0)">
    Remove `name` from the schema and stop reading it. The drop loses only values you already
    copied:

    ```bash theme={null}
    npx xanosdk deploy ./xano/index.ts --to workspace --dry-run                      # droppedColumns: users.name
    npx xanosdk promote v1.5.0 --branch v1.5.0 --allow-shared-schema-changes
    ```
  </Step>
</Steps>

On the workspace, each step can be rolled back to the one before it: switching live back to
v1.3.2's Xano branch serves logic that never reads `display_name`, and the column keeps its
values. On a tenant, deploying v1.3.2 again is a replace, so it drops `display_name` with the
values you backfilled; `name` still holds them, and the backfill can run again. Once v1.5.0
lands, `name` and its values are gone whatever you roll back to.

The same three steps cover a retype (add a column of the new type, backfill it, drop the old one)
and a column made required (backfill the nulls first, then require it).

## When to pass `--allow-shared-schema-changes`

Pass it on the run that lands the contract step, after someone has read `droppedColumns` and
checked that nothing still reads the column. Do not put it in a workflow that runs on every tag:
the flag is the only point in the release flow where a person confirms that live data changes.
[CI/CD](/govern/ci-cd#a-release-that-changes-a-table) shows how the pipeline hands that run to a
person.

<Warning>
  Back up a tenant or workspace in the Xano dashboard before a release that drops or rewrites a
  column. A rollback restores logic, not data. See
  [Rollback and recovery](/govern/rollback-and-recovery#table-changes-are-never-rolled-back).
</Warning>

## Next

[Drift](/govern/drift): keep the workspace and your project in step when someone edits in Xano.


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