Skip to content
kix /docs
Install the CLI

How-to guide Author packages and clusters

Compose multi-team clusters with mergeFragments

Combine separately owned namespace policy and package instances into one cluster definition.

Use kix.mergeFragments when different teams maintain parts of one cluster’s namespace and instance trees. Each fragment remains a normal Nix attrset, so it can live beside the code its team owns.

A fragment can contribute namespaces, instances, or both. This platform fragment adds policy for apps and owns a service in platform:

how-to/composition/platform-fragment.nix
namespaces.apps = {
labels."platform.example.com/tier" = "application";
annotations."platform.example.com/owner" = "platform";
};
instances.platform.status-api = {
package = packages.echo-server;
config.message = "Platform status";
};

View source on GitHub ↗

An application fragment can add labels to the same namespace and declare its own instances:

how-to/composition/storefront-fragment.nix
namespaces.apps.labels."app.kubernetes.io/part-of" = "storefront";
instances.apps.storefront = {
package = packages.echo-server;
config.message = "Storefront ready";
};

View source on GitHub ↗

Import each fragment into the cluster file with any arguments it needs. In this example, both imports receive packages:

how-to/composition/fragments-cluster.nix
platformFragment = import ./platform-fragment.nix { inherit packages; };
storefrontFragment = import ./storefront-fragment.nix { inherit packages; };

Pass the fragments in a list. Use namespacePolicies for policy owned by the cluster definition itself:

how-to/composition/fragments-cluster.nix
composition = kix.mergeFragments {
fragments = [
platformFragment
storefrontFragment
];
# Policies applied by the cluster owner merge with the team fragments.
namespacePolicies.apps.labels."platform.example.com/managed" = "true";
};

View source on GitHub ↗

Namespace attrsets merge recursively. Two fragments may add different labels, annotations, or quota fields to the same namespace. They may not set the same leaf, even to the same value. Kix treats any duplicate leaf as a namespace policy conflict.

namespacePolicies uses the same merge. Cluster-level policy can add leaves, but it cannot override or repeat a leaf set by a fragment.

Instance ownership is stricter. Defining the same instance name in the same namespace from two fragments is always an error.

Assign both outputs inside a cluster module:

how-to/composition/fragments-cluster.nix
namespaces = composition.namespaces;
instances = composition.instances { };

View source on GitHub ↗

composition.instances is a function so fragments may calculate their instance tree from shared arguments. Pass those arguments in place of { } when a fragment’s instances value is a function.

Evaluate the composed cluster:

kix-examples/
❱ kix check how-to-fragments
 TOOL       RESULT  DETAILS                      
 eval       pass    16 manifests evaluated       
 scorecard  pass    0 errors, 2 warnings, 0 info

Inspecting the generated apps Namespace confirms that labels and annotations from both teams and the cluster policy were retained:

kix-examples/ output excerpt offline capture
❱ kix build how-to-fragments --output json
Show outputHide output · 19 lines
{
  "kind": "Namespace",
  "metadata": {
    "name": "apps",
    "labels": {
      "app.kubernetes.io/managed-by": "kix",
      "app.kubernetes.io/part-of": "storefront",
      "kubernetes.io/metadata.name": "apps",
      "platform.example.com/managed": "true",
      "platform.example.com/tier": "application"
    },
    "annotations": {
      "kix.run/identity-hash": "y2nm039ddnq7w89q933whl2nq8z9xls0",
      "kix.run/package": "_cluster",
      "kix.run/package-namespace": "_cluster",
      "platform.example.com/owner": "platform"
    }
  }
}

Keep settings with a single owner where possible. The conflict errors are most useful when overlapping ownership is accidental.