Skip to content
Install the CLI

Reference CLI

upgrade

kix upgrade moves a project to a newer version of Kix. It builds every cluster with the version the project uses now, pins the project to the new version, and builds every cluster again. Then it compares the two builds and lists the release notes that apply to the project.

kix upgrade runs in the Kix version you invoke directly, even when kix.toml pins an older version. For each version it tests, it installs that version of Kix if needed and runs the build with it. It does not contact any cluster.

kix upgrade [--to <VERSION>] [--preview]
kix upgrade --ack <ID>...
FlagDefaultDescription
--to <VERSION>latestThe version to move to: an exact version such as 0.10.2, a minor such as 0.10 (its newest patch), or latest, the newest release that is not a prerelease.
--previewfalsePrint what the upgrade would do and the release notes that apply, and change nothing.
--ack <ID>...noneAcknowledge a change to stored data by its id or name, so that kix deploy goes ahead. Does nothing else.

kix upgrade starts from the exact version in kix.toml, such as kix = "0.9.1". When kix.toml names a minor or no version, it starts from the version of the project’s Kix library in flake.lock. When the target is not newer than that, it prints this and exits 0:

Already on the latest Kix release (0.12.1). Nothing to upgrade.

Every release of Kix publishes structured release notes beside its release archives, as kix-<version>-changes.json, listed in the release’s signed SHA256SUMS. kix upgrade fetches the notes of every release after the project’s version up to the target and checks each file against SHA256SUMS. A release made before structured release notes existed has none, and the first run of an upgrade says so:

Note: Kix 0.9.1 has no release notes; see CHANGELOG.md.

kix upgrade --preview lists every breaking, security, and upgrade note in the range, and every release that every cluster must deploy, grouped by what you must do. Added, changed, and fixed notes are counted. It changes nothing:

Kix 0.10.0 -> 0.12.1 (preview, no files changed)
6 changes between 0.10.0 and 0.12.1:
* may affect your 6 clusters (package name matches an instance in use)
Config changes required (will fail the build until updated):
* [K0003] caddy (0.11.0): `replicaCount` was renamed to `replicas`.
[K0005] echo-server (0.11.0): `port` was renamed to `servicePort`.
Behavior & data changes (builds cleanly, requires review before deploy):
[K0009] (0.11.0): Cluster-wide default network policy mode now drops
unmatched egress traffic in namespaces with at least one workload.
* [K0007] harbor (0.12.0, moves stored data): Registry blob metadata moved
to v2 layout; existing PVCs are migrated in place on first start.
Requires `kix upgrade --ack K0007` before `kix deploy`.
Security fixes (builds cleanly, recommended for this upgrade):
* [K0008] caddy (0.11.2, CVE-2026-4102): Fixes HTTP/2 CONTINUATION frame
flood.
Without upgrading: Set `caddy.http2 = false` in the cluster.
Notes:
* [metrics-port] caddy (0.11.2): Admin metrics endpoint now binds to
127.0.0.1:2019 by default.
14 minor feature and bugfix changes between 0.10.0 and 0.12.1 are not shown (see CHANGELOG.md).
`kix upgrade` will stop for [K0003], [K0005] until you make the config changes above.
Next: run `kix upgrade`.

A note names packages, and Kix sees only the instance names a cluster uses (from kix list packages --cluster <name>, run with the project’s current Kix). So Kix cannot tell which notes affect a project. It lists them all, and marks with * a note whose package name equals the name of an instance in use. An unmarked note can still affect an instance with another name. When the current Kix is not installed, the preview marks nothing. When the range has no breaking, security, or upgrade notes, it says No breaking, security, or upgrade notes between 0.10.0 and 0.12.1.

  1. Builds every cluster with the version the project uses now, with kix export <cluster> --for audit, into ~/.cache/kix/upgrade/<project>/before/. When a cluster does not build, it stops with exit status 2. Fix the project on its current version first.

  2. Pins the project to the target, installs it, and builds every cluster. Pinning writes the exact version into kix.toml and moves the Kix library in flake.lock as kix lib update does. When the library input in flake.nix names the project’s version as a tag, such as github:kix-run/kix/v0.9.1, ?ref=refs/tags/v0.9.1, or ?ref=v0.9.1 on any host, Kix moves that tag too, but only when exactly one Kix URL in flake.nix names it. When two or more do, such as a second input that pins a version of Kix built into an image, Kix changes nothing, names the lines, writes edit-needed into kix-upgrade.json, and exits 3 before it installs the target. Change the library input’s URL yourself, leave the others, and run kix upgrade again. When Kix cannot lock the new tag in flake.lock, or flake.lock still names another tag afterwards, Kix puts kix.toml, flake.nix, and flake.lock back as they were before that step, names the tag, and exits 2 or 3.

  3. When a cluster does not build with the target, takes one minor release at a time: the newest patch of each minor after the project’s, ending with the target. A project on a prerelease, such as 0.9.0-rc.1, takes the newest release of its own minor first. It stops at the first release a cluster does not build with, prints the end of each error and that release’s matching config changes, keeps each cluster’s full build output in a log file, leaves the project pinned to that release, and exits 2:

    Building 6 clusters with Kix 0.12.1... failed (lt1)
    Stepping one minor release at a time (0.11.2 -> 0.12.1):
    Building 6 clusters with Kix 0.11.2... failed (1 of 6 failed: lt1)
    Cluster lt1:
    error: The option `packages.caddy.replicaCount` does not exist.
    Full build log: ~/.cache/kix/upgrade/<project>/logs/0.11.2/lt1.log
    Matching change in Kix 0.11.0:
    [K0003] caddy: `replicaCount` was renamed to `replicas`.
    Stopped at Kix 0.11.2 (step 1 of 2 toward 0.12.1).
    kix.toml, flake.nix, and flake.lock are pinned to 0.11.2 so you can fix this step first.
    Next: fix the error above, then run `kix upgrade` to continue to 0.12.1.

    Fix the errors against that release, then run kix upgrade again. The next run reuses the builds from step 1 and the package list made then, tries that release again, and continues. So does a run after an interruption, since Kix writes kix-upgrade.json before it first pins the project. If the cached builds from step 1 are missing, Kix stops with an error. Delete kix-upgrade.json and run kix upgrade again; the comparison then starts from the version the project is pinned to now.

  4. Compares the first build with the last, cluster by cluster, and prints the objects added, removed, and changed. Clusters that changed the same way are printed together, with +, ~, and - for added, changed, and removed objects. A change is marked [review: <Kind>] when the object is a Secret, Role, ClusterRole, RoleBinding, ClusterRoleBinding, NetworkPolicy, CiliumNetworkPolicy, CiliumClusterwideNetworkPolicy, or Certificate, or an Ingress or Gateway whose TLS settings changed.

  5. Searches the files git tracks in the project for each command or flag a release note says was removed or changed, and prints file:line for each. It skips flake.lock, CHANGELOG.md, changes/, and files over 1 MB.

  6. Removes each version of Kix it installed only to build with, keeping the version the project used and the version it is now pinned to. It says so only with -v.

  7. Writes kix-upgrade.json in the project, and ends with what to review before you deploy:

    Upgraded to Kix 0.12.1, but review before deploying:
    1. 3 Secrets changed in cluster xdi1 (Secret/harbor-core@registry,
    Secret/harbor-exporter@registry, Secret/harbor-jobservice@registry).
    2. 5 objects changed in clusters lt1, xdi1; read the changes above, or run
    `kix diff <cluster>`, before you deploy.
    3. [K0007] moves stored data in harbor. Once you are ready for the
    migration, unblock deploy with:
    kix upgrade --ack K0007

    Any object that changed in any cluster is on this list, and the run exits 3. Only when no object changed and nothing needs a review does it end with Upgraded to Kix 0.12.1. Ready to deploy. and exit 0.

When a release between the project’s version and the target has a change that every cluster must deploy before it upgrades further, the upgrade ends at the newest patch of that release’s minor, and exits 3:

Upgraded to Kix 0.11.2, but review before deploying:
1. Kix 0.11.0 must be deployed to all clusters before continuing to 0.12.1
(`kix deploy` on 0.12.1 will refuse any cluster still on 0.10.0).
kix.toml, flake.nix, and flake.lock are pinned to 0.11.2.
Next: commit this 0.11.2 step and deploy every cluster with `kix deploy <cluster>`, then run `kix upgrade` to continue to 0.12.1.

kix deploy refuses a cluster that would skip the release.

A change that moves or reinterprets stored data with no error goes into kix-upgrade.json. Until someone acknowledges it, kix deploy refuses to run, prints the note, and names the command:

Deploy blocked: upgrade to Kix 0.12.1 includes an unacknowledged data migration.
No clusters were contacted.
[K0007] (0.12.0, moves stored data):
Registry blob metadata moved to v2 layout; existing PVCs are migrated in
place on first start.
Next: once you are ready for this migration, run:
kix upgrade --ack K0007
Then run `kix deploy` again.

kix upgrade --ack K0007 records the acknowledgement in kix-upgrade.json:

Acknowledged K0007 in kix-upgrade.json. You can now run `kix deploy`.

kix deploy --dry-run and kix plan are not blocked. Another kix upgrade also refuses until each change is acknowledged.

This check reads kix-upgrade.json, so it protects only a project that was upgraded with kix upgrade and kept the file. A project whose pins were moved by hand gets no refusal. Commit kix-upgrade.json with the upgrade.

FieldMeaning
schemakix.run/upgrade/v1
from, toThe version the upgrade started from, and the version it moved to.
statusdone, fix-needed (a build failed, or the run stopped part of the way), edit-needed (a person must edit flake.nix), needs-person, or required-stop.
stepsEach version the project was built with: version, result (ok, failed, or started for a step that stopped before it built), and failed, the clusters that did not build.
recordsThe ids (or names, for a note without an id) of the release notes that apply, by kind.
dataChangesThe changes to stored data: reference, release, and body.
acknowledgedThe data changes someone acknowledged with --ack.
sensitiveChangesHow many changed objects are sensitive.
cliHitsEach project line that uses a changed command or flag: text, file, line.
beforeThe directory of the builds made with the version the upgrade started from.
packagesInUseThe instances the project’s clusters install, as the version the upgrade started from listed them. Absent when Kix could not list them.

Programs that read the file must skip fields they do not know.

VariableEffect
KIX_RELEASE_SOURCEA site laid out like kix.run to fetch releases from, such as an internal mirror. See kix self.
XDG_CACHE_HOMEThe builds go under $XDG_CACHE_HOME/kix/upgrade/ in place of ~/.cache/kix/upgrade/.
  • 0 when the project builds with the target, no object changed in any cluster, and nothing needs a person, and with --preview or --ack.
  • 1 when the release index or a release’s notes cannot be fetched or verified, a version cannot be installed, or the project cannot be pinned.
  • 2 when a cluster does not build, with the version the project used or with a release the upgrade tried.
  • 3 when the project builds with the target and a person should read what changed: an object that changed in any cluster, a sensitive object change, a behavior or data change, or a release that every cluster must deploy first.