Subtitle: Mastering Declarative Configuration Options


If you’ve spent any time operating Kubernetes in production, you’ve hit the Wall of YAML. Helm charts nested inside other Helm charts, Kustomize overlays overriding overlays, and a sea of copy-pasted boilerplate that slowly drifts across dev, staging, and production environments.

Most platform engineering teams try to solve this with more template processing, leading to the infamous "Kubernetes configuration tax" where engineers spend more time writing string-replacement logic than writing core application code.

In this first part of our series, we'll dive deep into CUE (Configure, Unify, Execute) as a modern, type-safe configuration kernel. We'll explore its powerful declarative options, validation mathematics, and 13 real-world design patterns that demonstrate how to move away from string-replacement text hacks towards model-driven topologies.


CUE Features We Use

Before we delve into the mathematical design, it is helpful to visualize the powerful CUE features utilized within a modern declarative configuration engine:

FEATUREWHAT IT GIVES USWHERE WE USE IT
Definitions
#Name: {...}
Typed schemas validated at eval#App, #CeSite, #StackDns, #Topology
Unification
(#A & #B)
Merge structs with type-safe constraint#CeSite & #StackDns context merge into apps
Defaults
(*value | type)
Overridable values; consumer narrows only*"kafka:9092" | string; consumer sets concrete
String interpolation
"\(expr)"
Computed fields from sibling valuesFqdn: "\(AppName).\(ClusterName).\(Suffix)"
Pattern constraints
[pattern]: {...}
Schema for dynamic keys; apply to matching fields[=~"^dns-\\d+$"]: {...}; topology CE instances
Optional fields
name?: type
Omit from export when unset — renderapp injectsAppInstance?: string, TenantName?: string
@embed(file=...)Import YAML into CUE at eval time — no codegendomain/env/params.yaml, domain/net/ (planned)
Disjunctions
(a | b | c)
Constrained enums validated at evalflavor: *"prod" | "test"; site type constraints
Dynamic lookup
struct[key]
Index struct by field value at eval time_flavor.sizing[flavor.sizing]
@stack(dns)
CUE attributes
Metadata attributes travel through unificationBuild-time prefix tag; future: K8s labels
OCI module registry
cue.dev/x/...
Versioned upstream schemas & importable dependenciescue.dev/x/k8s.io; ArgoCD, Kyverno (planned)
cue export openapiBidirectional schema (CUE ↔ OAS/JSON Schema)Generate OpenAPI docs; Import Netbox OAS
cue cmd
(tool/exec, tool/http)
CUE tool commands — run scripts/APIs from CUE; pipeline: fetch → validatefetch-netbox (planned); generate-context (planned); import + output in one

The Mathematics of Validation: The Turned-T Operator ()

To understand how CUE guarantees security, we must briefly look at its mathematical foundations. Unlike scripting languages that execute sequentially, CUE is based on Lattice Theory. It models types and values within a single, ordered algebraic structure.

In CUE, types are values, and values are types. The universe of possibilities starts at the Top element (—representing all possible, unconstrained data) and terminates at the Bottom element (—represented by a literal "T" turned 180 degrees).

     Top ( ⊤ )      <-- Anything / Unconstrained
       /   \
   string   int     <-- Type constraints
     /       \
  "dev"       42    <-- Concrete values
     \       /
   Bottom ( ⊥ )     <-- Error / logical conflict / "Turned-T"

The Turned-T () represents a logical contradiction, validation failure, or schema conflict. When we merge two structures using the Unification operator (&), the CUE compiler performs a "meet" operation on the lattice.

Core Lattice Operators in CUE

Operator / ConceptLattice RepresentationCUE SyntaxPractical Meaning / BehaviorExampleEvaluated Output
Top ()Highest Element (any value)_ (underscore)Completely unconstrained. Any type or value satisfies this.x: _Any valid JSON structure
Bottom ()Lowest Element (error)(Compile error)Represents a type collision, constraint violation, or logical conflict.x: string & 42 (Bottom / Compilation Failure)
Meet (Unification)Greatest Lower Bound (GLB)&Combines two separate constraints or values into a single, merged contract.x: string & "dev""dev"
Join (Disjunction)Least Upper Bound (LUB)|Represents a choice between multiple alternatives (constrained options/enums).x: "prod" | "test""prod" | "test"
Subtyping (Constraint)Relation (A ⊑ B): (colon)Asserts that a value or concrete struct satisfies a schema definition.x: #AppValidated at build-time
Default ChoicePrimary preference pointer*default | typeDefines a default value to be used if no overriding choice is supplied.x: *"small" | string"small" (defaults to "small")

If we attempt to unify a field declared as CpuLimit: #CpuQuantity (e.g., matching a string pattern like "500m") with a conflicting raw integer value 42, the mathematical intersection collapses into (Bottom). CUE prevents the compilation from succeeding and flags the exact line of the type collision instantly. By making our configurations mathematically sound, CUE ensures that a path leading to is caught at compile-time—long before deployment payloads reach the cluster.


The Power of CUE: 13 Real-World Design Patterns

To understand why CUE is a paradigm shift, let's explore 13 concrete design patterns demonstrating how CUE replaces templating boilerplate with structural, typed logic.


Phase 1: Safe Data Ingestion & Transformation

Pattern 1: Embedding YAML directly into CUE

The CUE compiler can embed shared raw static assets (like parameter maps or base image lists) directly into modules, making it a practical data integration layer.

@extern(embed)

package env

import "mxc/pkg/envsubst"

_params: _ @embed(file="params.yaml")
_images: _ @embed(file="images.yaml")

This is an exceptionally strong pattern for configuration management:

  • Keep external source data in YAML when that is the most natural format (e.g., vendor lists, legacy charts).
  • Load it directly into CUE.
  • Apply type constraints and transformations.
  • Export cleanly when done.

Pattern 2: Reconstructing values with internal transformation logic

When raw data is embedded, values arrive as plain strings. If those strings contain environment variables ($VAR) or composite references, you need a way to resolve them safely.

This can be achieved via an internal CUE utility package, mxc/pkg/envsubst/envsubst.cue:

package envsubst

#Resolve: {
    #base:     _
    #override: _

    // merge base values and overrides
    // normalize them into strings
    // resolve composed references into final output
}

This utility is then consumed directly within our defaults definition:

_base: {
    for k, v in _params {(k): v}
    for k, v in _images {(k): v}
}

_resolved: (envsubst.#Resolve & {#base: _base, #override: {}}).out

Historically, writing this type of typed glue code was a high-friction adoption barrier. With AI-assisted development, however, these robust boilerplate structures can be generated in seconds, giving platform teams type-safe reference lookup engines without manual maintenance overhead.


Phase 2: Modeling Identity & Structure

Pattern 3: A shared application schema with computed fields

Platform engineers typically spread naming conventions, DNS patterns, and ingress rules across dozens of files, wiki pages, and pipelines. CUE consolidates this into a single, shared base schema in mxc/schema/apps.cue:

#App: k8s.#FieldSchemas & {
    AppName:         string
    AppInstance?:    string
    ClusterName:     *env.GC_NAME | string
    InternalDomain:  *env.FABRIC_DOMAIN | string
    Environment:     *"$ENV_NAME" | string
    TenantName?:     string
    FqdnSuffix:      *InternalDomain | string
    Fqdn:            "\(AppName).\(ClusterName).\(FqdnSuffix)"
}

This ensures a single, immutable contract:

  • One place to enforce naming conventions.
  • One place to define operational defaults.
  • Every single microservice instantly inherits the identical configuration structure.

Pattern 4: Helper packages for naming and identity

To avoid code duplication, we maintain focused helper packages. For example, mxc/pkg/identity.cue exposes a clean #AppIdentity block:

package mxc

import "mxc/domain/env"

#AppIdentity: {
    #instance:   string
    #cluster:    *env.GC_NAME | string
    #fqdnSuffix: *env.FABRIC_DOMAIN | string

    out: {
        AppName:     #instance
        ClusterName: #cluster
        FqdnSuffix:  #fqdnSuffix
        Fqdn:        "\(#instance).\(#cluster).\(#fqdnSuffix)"
    }
}

Pattern 5: Thin consumer overrides

One of the most elegant outcomes of this architectural model is how thin the final cluster-instantiation files remain. The shared library owns the schema, defaults, and composition rules. The consumer layer owns only the delta.

Take this snippet for an example application:

package exampleapp

import base "mxc/deploy/exampleapp"

base

appInstance: "example-app-prod1"

exampleApp: {
    LogLevel: "debug"
    database: name: "prod-db1"
}

This pattern completely prevents environments from drifting away from the core platform template over time.


Phase 3: Topology-Driven Topologies

Pattern 6: Shared deployment schemas

Instead of discovering deployment shapes from folder hierarchies alone, we model deployment topologies explicitly in CUE.

#Context: {
    namespace?:        string
    featureflagsList?: [...string]
}

#App: {
    enabled:                *true | bool
    appName?:               string
    appInstance?:           string
    packageSourceOverride?: string
}

#Instance: {
    enabled:       *true | bool
    packageSource: string
    flavor?:       string
    context:       *{} | #Context
    apps:          {[string]: #App & context}
}

CUE topology modeling makes your cluster structurally self-aware. You can programmatically validate that apps are routed only to clusters that actually support their required resources.

Pattern 7: Standalone stack modules

Instead of a single, monolithic configuration repository, CUE supports standalone stack modules. For example, a DNS stack can maintain its own isolated module file:

module: "mxc.io/dns"
language: version: "v0.12.0"

The stack divides its layout into two logical domains:

  1. stack-config.cue: Models pure operational data (DNS zones, IPs, records).
  2. stack-platform.cue: Handles deployment targets (ArgoCD or Kluctl configurations).

Phase 4: Declarative Code Generation

Pattern 8: Comprehensions for derived infrastructure data

CUE loop comprehensions allow platform engineers to generate repeated, safe operational definitions without manual copy-paste errors.

_nsProxy: {
    ns1: "mxc-dns-0"
    ns2: "mxc-dns-1"
}

dnsProxy: {
    for key, ns in _nsProxy {
        "\(key)": {
            name:        "mxc-dns-proxy-\(key)"
            namespace:   ns
            publicIpRef: key
            originRefs:  [for sk, _ in sites {"\(sk)/\(key)"}]
        }
    }
}

zones: {
    for siteKey, zoneUid in _zoneUids {
        "\(siteKey)": {
            uid:         zoneUid
            recordNames: _zoneRecords
        }
    }
}

This single block removes mechanical duplication while guaranteeing 100% declarative outputs.


Phase 5: Schema-Driven Sizing & Validation

Pattern 9: Parameter-surface schema validation

We can validate arbitrary parameters on the service boundary using regex-based key matching in CUE:

#ParamSchema: {
    [=~".*[Mm]emoryLimit$"]:    #MemoryQuantity
    [=~".*[Mm]emoryRequest$"]:  #MemoryQuantity
    [=~".*[Cc]puLimit$"]:       #CpuQuantity
    [=~".*[Cc]puRequest$"]:     #CpuQuantity
    [=~".*[Ss]torageSize$"]:    #StorageSize
    [=~".*[Rr]eplicas$"]:       #ReplicaCount
    [string]:                   #_FieldValue
}

This is incredibly powerful: the schema does not need to know every application field in advance. It automatically applies proper Kubernetes resource quantity constraints simply by matching parameter name suffixes!

Pattern 10: App packages combining schema, defaults, and flavors

By grouping schema, defaults, and flavor overrides together, a single component file contains the entire operational lifecycle:

package kafka

import (
    "strings"
    stack "mxc/deploy/dns"
    "mxc/schema"
)

appName:     "kafka"
appInstance: "kafka"
flavor:      schema.#FlavorSelector

kafka: stack.#App & #Kafka & {
    appName:       appInstance
    clusterName:   stack.clusterName
    featureflags:  strings.Join(stack.featureflagsList, " ")
    namespace:     *stack.namespace | _
    storageClass:  *stack.storageClass | _
}

kafka: _flavor[flavor.tier]

Pattern 11: Flavor-based sizing without file sprawl

Instead of maintaining giant values files for each environment, we encapsulate sizing choices as inherited flavors inside CUE:

#FlavorSizingDefaults: #FlavorSizingMap & {
    prod:          {}
    test:          {}
    dev1:          test
    staging:       {}
    preprod:       staging
    [string]:      {}
}

If we want to configure sizing on Grafana, we declare our resource requirements directly in its definition, selecting the sizing tier inside the topology:

grafana: xc.#App & {
    AppName:     appInstance
    CpuLimit:    *"1" | _
    MemoryLimit: *"1500Mi" | _
}

grafana: _flavor.sizing[flavor.sizing]

Phase 6: Service Relationships and Image Lifecycles

Pattern 12: Cross-package references instead of external wiring glue

In traditional Helm setups, connecting Service A to Service B's local cluster endpoint requires handwriting complex templates. In CUE, services can import other definitions directly, resolving endpoints at compile-time:

import harbor "mxc/deploy/gitops:harbor"

HarborRegistryEndpoint: *"harbor.\(harbor.harbor.Namespace).svc.cluster.local:443" | string

Pattern 13: Promoting versions safely via floating tags and pinned digests

Deploying to production demands a balance between developer speed and reproducibility. We handle this by separating our version declarations inside CUE:

  1. Human-facing intent: Declare module dependencies using semantic versions (1.8.x) or release streams (stable, release-2026-q3).
  2. Machine-facing execution: During the GitOps rendering and validation pipeline, the floating pointer is resolved into a concrete, immutable Image SHA (digest).

Because CUE compiles down to hard data files, the final rendered output contains the pinned digest. This gives developers the flexibility of using moving promotion handles, while guaranteeing that our production deployments are 100% reproducible and immune to upstream tag overwrites.


[!TIP] In the next part of this series, we will explore how these CUE features and design patterns are integrated into the actual MXC GitOps engine to drive our cluster deployments! CUE Configuration Kernel (Part 2/2)