# Handle stateful migration prompts safely

Kix stops a deployment when one stateful resource replaces another in the
same package slot. Treat this as a data-migration gate, not as an ordinary
confirmation prompt.

The migration gate applies only when one stateful resource replaces another.
If a stateful resource is removed without a replacement, Kix treats it as an
ordinary orphan. Running with `--prune` deletes it without a migration prompt.
See
[Deploy with dry-run, timeouts, pruning, and log/TUI output modes](/docs/how-to/operate-a-cluster/deploy-with-dry-run-timeouts-pruning-and-log-tui-output-modes/)
to see how the plan reports orphans before deletion.

The example changes the `data/volume` package from
`PersistentVolumeClaim/media-v1` at `5Gi` to
`PersistentVolumeClaim/media-v2` at `10Gi`.

## Review the pair before contacting the cluster

This example exports the current definition with its Kix provenance so it can
stand in for the old side of an offline diff:

<Command {...exportBefore} />

Compare the replacement definition with that saved state:

<Command expandable {...diff} />

Check the logical slot, source, target, and reason. Kix reports this pair
because both resources have `lifecycle = "stateful"`, occupy the same
`data/volume` slot, and have different Kubernetes identities.

## Prepare the data migration

Choose a procedure supported by the workload and storage provider. Before
changing the deployment:

1. make a recoverable backup or snapshot;
2. stop or quiesce writers;
3. copy or restore the data into the target;
4. verify the target data independently;
5. record how to return consumers to the source.

Kix detects the replacement but does not perform these steps. The exact copy
and verification commands depend on the application, volume provider, and
access mode, so they should live in the service's migration runbook.

## Confirm that the gate is active

An ordinary deployment refuses the pair even when `--yes` is present:

<Command expandable {...refusal} />

`--yes` skips the general deploy confirmation. It does not acknowledge data
loss risk.

## Preview the acknowledged deployment

After the data has been migrated and verified, repeat the API-server dry run
with the separate acknowledgement:

<Command expandable {...acceptedDryRun} />

`--accept-migrations` only allows the deployment to continue. It does not
copy data or verify that the target contains it. The warning about an empty
target is literal when the out-of-band migration has not happened.

Review the rest of the deployment plan. Do not add `--prune` while the source
PVC is still part of the rollback plan. Pruning has no separate safeguard for
stateful resources. Once the source PVC becomes an orphan, Kix deletes it like
any other orphan.

## Apply after verification

Run the acknowledged deployment without `--dry-run`:

<Command
  commands={[
    "kix deploy how-to-stateful-migration --accept-migrations",
  ]}
  cwd="kix-examples/"
/>

Confirm the application is using the target and validate its data before
retiring the source. Remove the old PVC only after the recovery window and
according to the storage provider's reclaim policy.

:::caution
Do not make `--accept-migrations` a default CI flag. A newly detected pair
needs its own reviewed migration plan.
:::

See [Preview changes with `kix diff`](/docs/how-to/operate-a-cluster/preview-changes-with-kix-diff/)
for the ordinary diff workflow.