Skip to content
Install the CLI

Reference Clusters and instances

kix.toml

kix.toml is an optional configuration file placed beside flake.nix at the root of a Kix project. It names the version of Kix the project uses (kix), and it chooses the project’s builder: whether Kix evaluates clusters with the Nix in the Kix runtime and Kix’s local store (builder = "kix", the default) or with the machine’s installed Nix and /nix/store (builder = "nix"). Because kix.toml lives in the repository, every contributor and CI job uses the same Kix version and builder without passing extra flags or environment variables.

Kix looks for kix.toml in the directory named by --flake (by default ., the current working directory). When --flake is a remote flake reference such as github:org/repo rather than a local directory, Kix uses the default builder ("kix").

kix.toml
kix = "0.8"
builder = "nix"

The file and both keys are optional. An absent kix.toml or an empty kix.toml is equivalent to:

builder = "kix"

kix.toml accepts only keys that the installed version of Kix recognizes. In this version of Kix, the valid settings are kix, builder, and the [upgrade] table. Unknown keys, unknown builder names, a kix value that is not a version, and TOML syntax errors stop the command before evaluation starts.

kix names the version of Kix that runs for this project:

ValueAccepts
"0.8"Any 0.8 patch release. Kix runs the newest 0.8 it has, the running one or an installed one.
"0.8.3"Only Kix 0.8.3.
"0.9.0-rc.1"Only the prerelease 0.9.0-rc.1.

A minor such as "0.9" never matches a prerelease. To try a prerelease in a project, name it in full, and change the setting back when the release is out.

Kix 0.7 and older refuse a kix.toml that sets kix, so the setting must name Kix 0.8 or newer. A value such as kix = "0.7" stops the command with an error.

Before Kix parses its command line, it reads kix from kix.toml in the directory named by --flake (or KIX_FLAKE), and then:

SituationWhat Kix does
No kix.toml, or no kix settingRuns
The running Kix matches, and no newer matching Kix is installedRuns
A matching Kix newer than the running one is installed in ~/.local/share/kix/Runs that Kix in its place, with the same arguments
No matching Kix is installedDownloads the newest matching release from kix.run, checks its signature and SHA-256, prints Installing Kix <version> (this project needs <kix>), and runs it
No matching Kix is installed, and KIX_AUTO_INSTALL=0Stops: This project needs Kix <kix> (kix.toml), and no Kix <kix> is installed. Automatic installs are off (KIX_AUTO_INSTALL=0). Run `kix self install <kix>`.

KIX_AUTO_INSTALL set to 0, false, or no stops Kix from downloading versions. kix self, kix completions, kix init, kix help, and --help run in the version you typed, whatever kix.toml says. A remote flake reference such as github:org/repo is not read. To choose, Kix reads kix.toml and lists ~/.local/share/kix/. It runs no Nix and makes no network request unless it has to install. So a project with kix = "0.8" moves to a new 0.8 patch as soon as one is installed.

At this stage Kix reads only the kix setting. It ignores other keys and values it does not know, so an older Kix can hand a project over to the newer Kix it names. The Kix that runs the command then checks the whole file.

kix --version follows the same rules, except that it never downloads. When no matching Kix is installed, it prints the running version and then, on stderr, this project needs Kix <kix>, which is not installed. Any other kix command installs it.

The Kix that hands over sets KIX_SELECTED_BY to its own path for the Kix it runs, and kix --version and kix doctor print it. A Kix that finds KIX_SELECTED_BY set runs without choosing again.

Kix also checks that the Kix library in flake.lock has the same minor version as Kix and a patch version no newer than Kix’s. Set kix to the Kix library’s minor so that everyone on the project runs a Kix that can build it.

ValueStatusNix binary and storeHow Helm charts are rendered
"kix"DefaultThe nix in the Kix runtime (2.35.4), with Kix’s local store at $XDG_CACHE_HOME/kix/store (or ~/.cache/kix/store, overridden by KIX_STORE_ROOT)Kix runs the helm programs in the Kix runtime outside Nix and writes chart tarballs and rendered JSON into Kix’s local store
"nix"Supportednix and nix-store from PATH, using /nix/store and the machine’s nix.confNix fetches charts as fixed-output derivations and runs helm template inside ordinary Nix builds during evaluation
"remote"ReservedRemote build service (not yet implemented)Refused by this version of Kix

When builder is "kix" (or when kix.toml is omitted), Kix runs the nix, nix-store, helm, kubectl, and sops binaries from the Kix runtime in libexec/kix/. It writes evaluated manifests and rendered Helm charts into Kix’s local store at $XDG_CACHE_HOME/kix/store (or ~/.cache/kix/store when XDG_CACHE_HOME is unset).

This mode requires no Nix installation on the machine, no Nix daemon, no /nix directory, no root access, and no Linux user namespaces.

When kix.toml sets builder = "nix", Kix runs nix and nix-store from PATH against the machine’s /nix/store. It inherits the machine’s and user’s Nix configuration (nix.conf), including binary caches (substituters), remote build machines (builders), and access-tokens.

Use builder = "nix" when your project needs any of the following:

  • Shared Nix binary caches or remote builders configured in nix.conf.
  • Plain nix build or nix flake check on clusters that include Helm charts.
  • The packages.<system>.cluster-<name>-activation flake output for scripts or CI pipelines that build activations directly with nix build.

Under builder = "nix", both kix and plain nix commands render Helm charts inside ordinary Nix derivations using the official Helm release binary pinned in kix/lib/helm-versions.json (4.3.1 for helmVersion = "4" and 3.19.1 for helmVersion = "3", matching the binaries shipped in libexec/kix/). Both builders pass the same helm template flags, so a chart renders the same way under either builder. For the Helm clusters in the Kix repository, both builders give identical manifests.

Even when builder = "nix", Kix still runs kubectl, sops, and any direct CLI helm invocations from the Kix runtime in libexec/kix/ rather than PATH.

builder = "remote" is reserved for a build service that builds the project on another machine. This version of Kix refuses it:

<path>/kix.toml sets builder = "remote", but remote builders are not supported yet. Set builder = "kix", or remove the setting

The [upgrade] table sets how kix upgrade picks the release it moves the project to:

[upgrade]
min-age = "7d"
KeyValueEffect
min-ageA number of days, such as "7d"kix upgrade picks only releases at least this old, by their release date.

Nix flakes only see files that Git tracks. When kix.lib.mkFlake evaluates your flake, it reads ${inputs.self}/kix.toml inside Nix and exposes the chosen builder at legacyPackages.<system>.kixConfig.builder.

Before evaluating a cluster, kix compares the kix.toml file on disk with legacyPackages.<system>.kixConfig.builder. If you create kix.toml with builder = "nix" and do not stage it in Git, Nix does not copy kix.toml into the flake source tree, the Kix library falls back to "kix", and kix stops with an error:

./kix.toml is not tracked by Git, so Nix ignores it. Run `git add kix.toml`

Stage kix.toml whenever you add or change it:

❱ git add kix.toml

Two other conditions must hold for the CLI and the flake library to agree:

  1. flake.nix must pass inputs (which includes self) to kix.lib.mkFlake { inherit inputs; ... }, so mkFlake can locate ${inputs.self}/kix.toml.
  2. The kix flake input locked in flake.lock must be new enough to expose kixConfig. If the locked library predates kix.toml support, kix prompts you to run kix lib update.

When a project sets builder = "nix", the machine running kix must meet these requirements:

  • Nix 2.24 or later on PATH. The Kix library uses the |> pipe operator (pipe-operators), which Nix added in 2.24.
  • Upstream Nix, not Lix. Lix reports (Lix, like Nix) in nix --version and is refused because this builder relies on upstream Nix’s flake and pipe-operator behavior.
  • allow-import-from-derivation enabled (true). This is the default in Nix. When builder = "nix", scope.helm.importChart and kix.helmChart build a derivation that runs helm template and import the rendered JSON during evaluation (Import From Derivation, or IFD). If allow-import-from-derivation is set to false in nix.conf, evaluating a cluster that uses Helm charts fails.
  • No trusted-users requirement. The nix builder uses ordinary fixed-output derivations for chart downloads and standard derivations for chart rendering. Your user account does not need to be listed in trusted-users on the Nix daemon.
  • KIX_STORE_ROOT must be unset. KIX_STORE_ROOT only redirects the local store of the kix builder. If KIX_STORE_ROOT is set in the environment for a project with builder = "nix", kix stops and asks you to unset KIX_STORE_ROOT.

Run kix doctor in the project directory to check kix.toml, the machine’s nix binary, allow-import-from-derivation, and whether the Nix store trusts your user:

❱ kix doctor

Setting builder = "nix" in kix.toml changes what kix.lib.mkFlake exports in your flake:

  • packages.<system>.cluster-<name>-activation is exported. This output creates a directory linking activation (the Activation resource manifest), kix-packages.json, kix-scorecard.json, kix-extra-images.json, kix-image-sources.json, kix-interface-*.json, and kix-activation-index.json. You can build it with nix build and pass the result to kix diff --from. Projects using the default kix builder omit this output because they evaluate into ~/.cache/kix/store without building derivations in /nix/store.

  • packages.<system>.cluster-<name> and checks.<system>.* support Helm charts. Under the default kix builder, Kix renders Helm charts outside Nix, so plain nix build and nix flake check cannot build clusters that use Helm charts. Under builder = "nix", mkFlake renders Helm charts through Nix, so packages.<system>.cluster-<name> and the cluster checks (schema-cluster-<name>, rules-cluster-<name>, and pi-wiring-cluster-<name>) work with plain nix build and nix flake check.

  • legacyPackages.<system>.kixClustersNix.<name> is used by kix. Alongside legacyPackages.<system>.kixClusters.<name>, mkFlake exposes kixClustersNix.<name> evaluated with the Nix Helm route. When builder = "nix", the kix CLI evaluates kixClustersNix.<name> so kix build, kix plan, and kix deploy share the exact derivations that nix build produces.

  • legacyPackages.<system>.kixLib holds the library for the builder. It has kix and packages, as a cluster function receives them, with Helm charts rendered by Nix under builder = "nix". A flake that merges mkFlake into a larger flake uses it for its own checks.

When you invoke kix, it automatically passes --extra-experimental-features "nix-command flakes pipe-operators" to nix. When you run nix build or nix flake check directly from your shell, enable those three experimental features on the command line or in nix.conf:

❱ nix build --extra-experimental-features "nix-command flakes pipe-operators" .#cluster-prod-activation

By default, kix.lib.mkFlake generates outputs for four platforms: x86_64-linux, aarch64-linux, aarch64-darwin, and x86_64-darwin. nix flake check checks only the machine’s own platform unless you pass --all-systems.

If a cluster uses Helm charts under builder = "nix", evaluating that cluster imports the output of a chart-rendering derivation (import-from-derivation). With --all-systems, Nix must build those derivations for every platform the flake lists. On a machine without remote builders for the other platforms, nix flake check --all-systems fails when it tries to build a chart derivation for another platform.

To avoid needing builders for platforms you do not use, pass systems to kix.lib.mkFlake with only the systems your team and CI build on:

flake.nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
kixpkgs.url = "github:kix-run/kix";
kixpkgs.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = inputs:
inputs.kixpkgs.lib.mkFlake {
inherit inputs;
systems = [ "x86_64-linux" ];
clusters.prod = ./clusters/prod.nix;
};
}
ConditionError message
Invalid TOML syntax<path> is not valid TOML: line <N>: <reason>
Unknown key in kix.toml<path> has an unknown setting `<key>` (Kix <version> supports: builder, kix). Check the spelling, or upgrade Kix if the project needs a newer version
kix is not a version, such as kix = 8 or kix = "latest"<path> sets kix = <value>, which is not a Kix version. Write a minor such as kix = "0.8", an exact version such as kix = "0.8.3", or a prerelease such as kix = "0.9.0-rc.1"
kix is a number, such as kix = 0.8<path> sets kix = 0.8 as a number. Write it in quotes: kix = "0.8"
kix names Kix 0.7 or older, such as kix = "0.7"<path> sets kix = "0.7", but Kix 0.7 and older cannot read this setting. Name Kix 0.8 or newer, or remove the line.
kix names a version that is not installed, with KIX_AUTO_INSTALL=0This project needs Kix <kix> (kix.toml), and no Kix <kix> is installed. Automatic installs are off (KIX_AUTO_INSTALL=0). Run `kix self install <kix>`.
Unknown builder value<path> sets builder = "<value>", which is not a known builder (Kix <version> supports: kix, nix, remote). Check the spelling, or upgrade Kix if the project needs a newer version
builder without quotes, such as builder = 3<path> sets builder to a number. Write the builder's name in quotes, such as builder = "kix" (Kix <version> supports: kix, nix, remote)
builder = "remote"<path> sets builder = "remote", but remote builders are not supported yet. Set builder = "kix", or remove the setting
builder = "nix" in kix.toml, but kix.toml is not tracked by Git<path> is not tracked by Git, so Nix ignores it. Run `git add kix.toml`
builder = "nix" in kix.toml, but the flake publishes no legacyPackages.<system>.kixConfig<path> sets builder = "nix", which this project's flake does not support. If flake.nix calls kixpkgs.lib.mkFlake, run `kix lib update` to update the Kix library in flake.lock. If flake.nix builds Kix outputs directly (for example with kixpkgs.lib.forPkgs), switch to kixpkgs.lib.mkFlake as shown in "Use mkFlake in a consuming repo" in the docs
KIX_STORE_ROOT set when builder = "nix"KIX_STORE_ROOT is set, but it does not apply to this project. The project's builder is "nix", which uses the machine's Nix and its store. Unset KIX_STORE_ROOT
nix not found on PATH when builder = "nix"this project uses the `nix` builder (`builder = "nix"` in kix.toml), but `nix` is not on PATH. Install Nix 2.24 or later, or remove `builder = "nix"` from kix.toml
Nix older than 2.24 on PATHthis project uses the `nix` builder (`builder = "nix"` in kix.toml), which requires Nix 2.24 or later, but `nix --version` reported <version>. Upgrade Nix, or remove `builder = "nix"` from kix.toml
Lix on PATHthis project uses the `nix` builder (`builder = "nix"` in kix.toml), which does not support Lix (`nix --version` reported <version>). Install Nix 2.24 or later, or remove `builder = "nix"` from kix.toml