How-to guide / Start and inspect a Kix project
Use mkFlake in a consuming repo
Use kixpkgs.lib.mkFlake in the repository that owns your cluster definitions.
It exposes the cluster outputs that Kix discovers.
Add the flake inputs
Section titled “Add the flake inputs”Create a flake.nix and declare nixpkgs and kixpkgs:
1{2 description = "Application infrastructure";3
4 inputs = {5 nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";6 kixpkgs.url = "github:kix-run/kix";7 kixpkgs.inputs.nixpkgs.follows = "nixpkgs";8 };9
10 outputs = inputs: inputs.kixpkgs.lib.mkFlake {11 inherit inputs;12 clusters.production = ./clusters/production.nix;13 };14}Following the same nixpkgs input keeps package evaluation on one nixpkgs revision.
Register cluster files
Section titled “Register cluster files”The examples repository registers each cluster by name:
24 outputs =25 inputs:26 inputs.kixpkgs.lib.mkFlake {27 inherit inputs;28 clusters = {29 "02-hello-world" = ./tutorials/02-hello-world/cluster.nix;30 "06-service-dep" = ./tutorials/06-service-dep/cluster.nix;31 "08-namespace-deps" = ./tutorials/08-namespace-deps/cluster.nix;32 "09-typed-options" = ./tutorials/09-typed-options/cluster.nix;33 "10-reuse-packages" = ./tutorials/10-reuse-packages/cluster.nix;34 "19-scorecards" = ./tutorials/19-scorecards/cluster.nix;35 "how-to-application" = ./how-to/application/cluster.nix;36 "how-to-adoption" = ./how-to/adoption/cluster.nix;37 "how-to-stateful-migration" = ./how-to/adoption/stateful-before-cluster.nix;38 "how-to-adoption-takeover" = ./how-to/adoption/takeover-cluster.nix;39 "how-to-helm-bridge" = ./how-to/adoption/helm-bridge-cluster.nix;40 "how-to-auto-instantiation" = ./how-to/auto-instantiation/cluster.nix;41 "how-to-composition" = ./how-to/composition/cluster.nix;42 "how-to-fragments" = ./how-to/composition/fragments-cluster.nix;43 "how-to-multi-env" = ./how-to/composition/multi-env-cluster.nix;44 "how-to-package-storage" = ./how-to/package-stacks/storage-cluster.nix;45 "how-to-package-stackgres" = ./how-to/package-stacks/stackgres-cluster.nix;46 "how-to-package-monitoring" = ./how-to/package-stacks/monitoring-cluster.nix;47 "how-to-package-monitoring-loki" = ./how-to/package-stacks/monitoring-loki-cluster.nix;48 "how-to-package-cilium" = ./how-to/package-stacks/cilium-cluster.nix;49 "how-to-package-valkey" = ./how-to/package-stacks/valkey-cluster.nix;50 "how-to-package-velero" = ./how-to/package-stacks/velero-cluster.nix;51 "how-to-package-victoria-metrics" = ./how-to/package-stacks/victoria-metrics-cluster.nix;52 "how-to-platform-gateway" = ./how-to/platform/gateway-cluster.nix;53 "how-to-platform-hostpath" = ./how-to/platform/hostpath-cluster.nix;54 "how-to-platform-ingress" = ./how-to/platform/ingress-cluster.nix;55 "how-to-platform-monitoring" = ./how-to/platform/monitoring-cluster.nix;56 "how-to-platform-network-policy" = ./how-to/platform/network-policy-cluster.nix;57 "how-to-platform-secrets" = ./how-to/platform/secrets-cluster.nix;58 "how-to-platform-sops" = ./how-to/platform/sops-secrets-cluster.nix;59 "how-to-platform-cloudflare-tunnel" = ./how-to/platform/cloudflare-tunnel-cluster.nix;60 # The homelab scenario: one service set and its migration variants.61 "homelab-kind" = ./how-to/homelab/cluster-kind.nix;62 "homelab-kind-gateway" = ./how-to/homelab/cluster-kind-gateway.nix;63 "homelab-kind-gateway-migrate" = ./how-to/homelab/cluster-kind-gateway-migrate.nix;64 "homelab-kind-tls" = ./how-to/homelab/cluster-kind-tls.nix;65 "homelab-kind-tls-migrate" = ./how-to/homelab/cluster-kind-tls-migrate.nix;66 "homelab-kind-upgrade-small" = ./how-to/homelab/cluster-kind-upgrade-small.nix;67 "homelab-kind-upgrade-broad" = ./how-to/homelab/cluster-kind-upgrade-broad.nix;68 "homelab-kind-pvc-resize" = ./how-to/homelab/cluster-kind-pvc-resize.nix;69 "homelab-kind-storage-migrate" = ./how-to/homelab/cluster-kind-storage-migrate.nix;70 "homelab-kind-db-resize" = ./how-to/homelab/cluster-kind-db-resize.nix;71 "homelab-kind-ns-rename" = ./how-to/homelab/cluster-kind-ns-rename.nix;72 "homelab-kind-pg17" = ./how-to/homelab/cluster-kind-pg17.nix;73 "homelab-kind-env-stamped" = ./how-to/homelab/cluster-kind-env-stamped.nix;74 "homelab-kind-env-stamped-dev-change" = ./how-to/homelab/cluster-kind-env-stamped-dev-change.nix;75 };76 };Each value under clusters is a cluster function. Its attribute name is the
cluster name you pass to the CLI, and, unless the file passes name to
kix.buildCluster, the name Kix records in the manifests and the Activation
record. A cluster listed here needs no name of its own.
Keep the name of a cluster that Kix 0.6 deployed
Section titled “Keep the name of a cluster that Kix 0.6 deployed”Kix 0.6 named a cluster cluster when its file passed no name to
kix.buildCluster. Kix 0.7 names it after its key, so its deploy records no
longer match. kix deploy and kix plan refuse such a cluster before they
apply anything: its file passes no name, the Kubernetes cluster has no
Activation records for the key, and it has records for a Kix cluster named
cluster. Fix it in the cluster file in one of two ways:
- Add
name = "cluster";to thekix.buildClustercall to keep the old name and its deploy history. - Add
name = "<key>";to confirm the new name. The cluster then starts a new deploy history. The oldclusterrecords stay on the Kubernetes cluster, and Kix never deletes the objects that only the old build has, so remove them yourself.
Either value turns the check off.
For a single project, a compact registration is enough:
1outputs = inputs: inputs.kixpkgs.lib.mkFlake {2 inherit inputs;3 clusters.application = ./cluster.nix;4};Apply one setting to every cluster
Section titled “Apply one setting to every cluster”clusterModules lists modules every cluster in the flake starts from, ahead
of the cluster’s own. Use it for a setting the repository wants everywhere,
such as making scorecard findings fail the build:
1outputs = inputs: inputs.kixpkgs.lib.mkFlake {2 inherit inputs;3 clusters.production = ./clusters/production.nix;4 clusterModules = [ { scorecard.maxSeverity = "error"; } ];5};A cluster that needs a different value sets the option itself with
lib.mkForce.
Check the packages the repository defines
Section titled “Check the packages the repository defines”Evaluating a cluster does not check the
option contract.
List the packages the repository defines under packages, and the flake
gets the check option-contract-<name> for each one:
1outputs = inputs: inputs.kixpkgs.lib.mkFlake {2 inherit inputs;3 clusters.production = ./clusters/production.nix;4 packages.billing-api = ./packages/billing-api;5};nix flake check then fails when a default of billing-api would be
partly discarded by an instance that sets part of the option, at any
availability level the package can run at.
Use mkFlake inside a larger flake
Section titled “Use mkFlake inside a larger flake”A repository whose flake also builds other things, such as NixOS machines or
container images, can still use mkFlake for its Kix outputs. Call it in a
let binding and merge its packages, checks, and legacyPackages into
the flake’s own, one system at a time:
1outputs =2 inputs:3 let4 systems = [ "x86_64-linux" "aarch64-darwin" ];5 forAllSystems = inputs.nixpkgs.lib.genAttrs systems;6 kixOutputs = inputs.kixpkgs.lib.mkFlake {7 inherit inputs systems;8 clusters.production =9 { kix, packages }:10 import ./clusters/production.nix {11 inherit kix packages;12 shared = import ./clusters/shared.nix { inherit kix; };13 };14 };15 in16 {17 nixosConfigurations.web-1 = ...;18
19 packages = forAllSystems (20 system: kixOutputs.packages.${system} // { deploy-tool = ...; }21 );22 checks = forAllSystems (23 system:24 kixOutputs.checks.${system}25 // {26 policy = import ./checks/policy.nix {27 inherit (kixOutputs.legacyPackages.${system}.kixLib) kix packages;28 };29 }30 );31 legacyPackages = forAllSystems (system: kixOutputs.legacyPackages.${system});32 };- A cluster that needs more arguments is given as a function.
mkFlakepasses itkixandpackages, and the function passes the rest to the cluster file. Build anything the cluster uses, such assharedabove, from thekixthe function receives. - A check or tool outside the clusters takes the library from
legacyPackages.<system>.kixLib. It holdskixandpackages, set up for the builder inkix.toml, so it renders Helm charts the same way as the clusters. - Keep your own output names apart from Kix’s.
//keeps the right-hand value when two names clash, without an error. Kix’s outputs start withcluster-,schema-cluster-,rules-cluster-,pi-wiring-cluster-,option-contract-, and, underlegacyPackages,kix.
Choose a project builder (optional)
Section titled “Choose a project builder (optional)”By default (builder = "kix"), Kix evaluates your project with the Kix
runtime and Kix’s local store (~/.cache/kix/store). If your project needs the
machine’s Nix installation and its configured binary caches or remote builders,
add kix.toml beside flake.nix and stage it in
Git:
1builder = "nix"❱ git add kix.toml See kix.toml for the full builder reference.
Lock the inputs
Section titled “Lock the inputs”Pin the Kix library (kixpkgs in flake.lock) to match your installed Kix:
❱ kix lib update Commit flake.nix and flake.lock together. Other machines and CI will then
evaluate the same Kix and nixpkgs revisions.
Verify CLI discovery
Section titled “Verify CLI discovery”List the clusters exposed by the flake:
❱ kix list clusters
NAME
02-hello-world
06-service-dep
08-namespace-deps
09-typed-options
10-reuse-packages
19-scorecards
homelab-kind
homelab-kind-db-resize
homelab-kind-env-stamped
homelab-kind-env-stamped-dev-change
homelab-kind-gateway
homelab-kind-gateway-migrate
homelab-kind-ns-rename
homelab-kind-pg17
homelab-kind-pvc-resize
homelab-kind-storage-migrate
homelab-kind-tls
homelab-kind-tls-migrate
homelab-kind-upgrade-broad
homelab-kind-upgrade-small
how-to-adoption
how-to-adoption-takeover
how-to-application
how-to-auto-instantiation
how-to-composition
how-to-fragments
how-to-helm-bridge
how-to-multi-env
how-to-package-cilium
how-to-package-monitoring
how-to-package-monitoring-loki
how-to-package-stackgres
how-to-package-storage
how-to-package-valkey
how-to-package-velero
how-to-package-victoria-metrics
how-to-platform-cloudflare-tunnel
how-to-platform-gateway
how-to-platform-hostpath
how-to-platform-ingress
how-to-platform-monitoring
how-to-platform-network-policy
how-to-platform-secrets
how-to-platform-sops
how-to-stateful-migration If the flake is not in the current directory, pass it explicitly:
❱ kix list clusters --flake ./infrastructure You can now use the discovered names with check, build, diff, deploy,
and the other cluster commands.