Skip to content

kix.keep

kix.keep container

Marks a container “never collapse to absent”. Use it in constructors that build a presence-meaningful field (an emptyDir volume source, a label selector) from optional arguments that may all be null.

InputResult
AttrsetThe same attrset plus an additive _kixKeep marker. Resolved at mkResource; the marker never reaches rawManifest, the identity JSON, or the rendered output.
ListNormalized eagerly: null elements dropped; [ ] returned if nothing survives. No marker, because Nix merges replace lists wholesale, so a kept list cannot be re-filled with nulls later.
Anything elseThrows.

Rendering applies the collapse rule, bottom-up:

  • null values are dropped.
  • A container that had members and lost all of them collapses to null and is omitted; the collapse cascades upward through wrappers.
  • A container written literally empty ({ }, [ ]) renders as {}/[].
  • Null list elements are dropped; an element that collapses entirely leaves its list.

kix.keep overrides the second point for one container: it renders {} even when every member was null.

OperationResult
lib.recursiveUpdate kept { field = value; }Field merges in; keep is preserved.
lib.recursiveUpdate kept { field = null; }Keep is preserved; the container still renders {} if everything collapses.
attrs // { key = replacement; }Wholesale replacement discards the keep, matching the author’s intent: the value was replaced.
kix.keep (kix.keep x)Same as applying it once.
  • An explicit empty value (emptyDir = { };) renders as-is. No keep required.
  • A constructor that filters its own nulls (lib.optionalAttrs) produces a literal empty and needs no keep. kix.mount.emptyDir works this way.
  • CRD schema subtrees rarely need it: the collapse rule keeps their literal empties (properties = { };) as written.