8.0 KiB
The Complete Technical Guide to CUE (Configure-Unify-Execute)
A structured, practical, and comprehensive introduction to CUE—covering core concepts, real-world applications, and best practices.
1. Introduction to CUE
What is CUE?
CUE (Configure-Unify-Execute) is an open-source data constraint language developed at Google. It is designed for:
- Configuration management (Kubernetes, Terraform, CI/CD)
- Data validation (API schemas, input sanitization)
- Code generation (Dockerfiles, Kubernetes manifests, SQL schemas)
- Policy enforcement (security rules, compliance checks)
Unlike YAML/JSON, CUE merges types, values, and constraints into a single model, enabling deterministic, reproducible configurations.
Why CUE Over Alternatives?
| Tool | Strengths | Weaknesses vs. CUE |
|---|---|---|
| YAML | Human-readable, widely used | No validation, no logic, fragile |
| Jsonnet | Templating, code reuse | Slower, no built-in validation |
| HCL | Terraform integration | Less flexible for non-TF use |
| Pulumi | Full programming model | Complex, runtime-dependent |
| CUE | Validation + unification | Steeper initial learning curve |
2. Core Concepts
The CUE Lattice
CUE’s power comes from its lattice structure, where:
_(Top): Accepts any value (e.g.,string,int,{})._|_(Bottom): An invalid/conflicting value (error state).- Unification (
&) combines constraints (like logical AND). - Disjunction (
|) allows alternatives (like logical OR).
Example:
#Schema: {
name: string & =~"^[A-Z][a-z]+$" // Must start with uppercase
age: int & >0 & <120 // Age between 0 and 120
role?: "admin" | "user" // Optional role
}
valid: #Schema & { name: "Alice", age: 30 } // ✅ Valid
invalid: #Schema & { name: "alice", age: 150 } // ❌ Fails (name, age)
3. Getting Started
Installation
# Install CUE
brew install cue-lang/tap/cue # macOS
sudo apt-get install cue # Debian/Ubuntu
go install cuelang.org/go/cmd/cue@latest # Go users
# Verify
cue version
Basic Workflow
- Define schemas (
.cuefiles). - Validate data (
cue vet). - Export to JSON/YAML (
cue export).
Example:
// schema.cue
#Person: {
name: string
age: int & >=18
}
// data.json
{ "name": "Bob", "age": 25 }
# Validate
cue vet schema.cue data.json # ✅ Passes
4. Real-World Use Cases
Case 1: Kubernetes Configuration
Problem: YAML files are brittle and hard to validate.
Solution: Define a reusable schema.
// k8s.cue
#Deployment: {
apiVersion: "apps/v1"
kind: "Deployment"
metadata: name: string
spec: {
replicas: int & >=1
template: spec: containers: [{
name: string
image: string & =~".+:.+"
}]
}
}
myapp: #Deployment & {
metadata: name: "webapp"
spec: replicas: 3
spec: template: spec: containers: [{ name: "app", image: "nginx:latest" }]
}
# Export to YAML
cue export k8s.cue -e myapp --out yaml > deploy.yaml
Case 2: Terraform Guardrails
Problem: Prevent invalid cloud configurations.
Solution: Enforce AWS/GCP policies.
#AWS: {
region: "us-east-1" | "us-west-2"
instanceType: "t2.micro" | "t3.medium"
}
my_vm: #AWS & {
region: "us-east-1"
instanceType: "t2.micro" # ✅ Valid
}
invalid_vm: #AWS & {
region: "eu-west-1" # ❌ Fails (invalid region)
}
Case 3: CI/CD Pipeline-as-Code
Problem: YAML-based pipelines are hard to maintain.
Solution: Define pipelines in CUE.
#Pipeline: {
steps: [...{
name: string
cmd: string
}]
}
my_pipeline: #Pipeline & {
steps: [
{ name: "build", cmd: "go build" },
{ name: "test", cmd: "go test" },
]
}
# Generate GitHub Actions YAML
cue export pipeline.cue --out yaml > .github/workflows/ci.yml
5. Debugging & Best Practices
Debugging Unification Errors
- Use
cue eval -vto trace unification steps. - Check for
_|_(bottom) in output—indicates conflicts.
Best Practices
- Modularize: Split schemas into files (
schemas/,configs/). - Reuse: Leverage CUE’s import system (
import "acme.com/schemas"). - Validate Early: Run
cue vetin CI/CD.
6. Advanced Topics
Go + CUE Integration
Embed CUE in Go programs for dynamic validation:
package main
import (
"cuelang.org/go/cue/cuecontext"
"fmt"
)
func main() {
ctx := cuecontext.New()
schema := ctx.CompileString(`
#Person: {
name: string
age: int & >=18
}`)
data := ctx.CompileString(`{ name: "Alice", age: 30 }`)
unified := schema.Unify(data)
if err := unified.Validate(); err != nil {
fmt.Println("Validation failed:", err)
} else {
fmt.Println("Valid!")
}
}
Generating Code
Convert CUE to:
- OpenAPI:
cue export --out openapi - Go Structs:
cue get go - SQL: Use templates (
text/template).
7. Learning Resources
- Official Docs: cuelang.org
- Playground: cuelang.org/play
- Community: CUE Slack
Conclusion
CUE replaces ad-hoc YAML/JSON with structured, validated, and reusable configurations. By mastering:
- Lattice logic (unification, constraints),
- Real-world workflows (K8s, Terraform, CI/CD),
- Tooling integration (Go, OpenAPI),
You can eliminate configuration errors and enforce policies declaratively.
Next Step: Try the CUE Tutorial or experiment in the playground! 🚀
Here’s a Mermaid.js diagram that visually explains the CUE lattice (Top, Bottom, Unification, and Disjunction) in a way that’s both accurate and appealing for visual learners. You can embed this directly in your Gitea Markdown files (if Mermaid rendering is enabled):
Diagram Explanation:
-
⊤ (Top)- The root of all possible values (e.g.,
string,int,{}). - Branches into concrete values (like
"Alice") and constraints (like>=18).
- The root of all possible values (e.g.,
-
Unification (
&)- Merges constraints (like a strict AND gate).
- Outputs either a valid value (if constraints are met) or
⊥(Bottom) (if conflicts exist).
-
Disjunction (
|)- Represents alternatives (like a flexible OR gate).
- Outputs the first valid alternative (e.g.,
"admin" | "user").
-
⊥ (Bottom)- The "error state" (e.g.,
name: 42whenstringis required).
- The "error state" (e.g.,
Why This Works:
- Visualizes the Lattice: Shows how CUE narrows possibilities from
⊤to valid outputs. - Color-Coded: Green (Top), Blue (Valid), Red (Error), Orange (Alternatives).
- Includes Examples: Embedded real CUE snippets for clarity.
Alternate Version (Simpler):
If you prefer a minimalistic view:
graph LR
T["⊤ (Any Value)"] -->|Unification (&)| U["Valid"]
T -->|Conflict| B["⊥ (Invalid)"]
T -->|Disjunction (|)| D["A | B | C"]
%% CUE Lattice Diagram
graph TD
A["⊤ (Top)"] --> B["Concrete Values"]
A --> C["Constraints"]
B --> D["Unification (&)"]
C --> D
D --> E["Valid Output"]
D --> F["⊥ (Bottom, Invalid)"]
B --> G["Disjunction (|)"]
C --> G
G --> H["Valid Alternative"]
style A fill:#4CAF50,stroke:#388E3C
style F fill:#F44336,stroke:#D32F2F
style E fill:#2196F3,stroke:#1976D2
style H fill:#FF9800,stroke:#F57C00
%% Examples
I["Example:\nname: string & =~'^[A-Z]'"] --> D
J["Example:\nrole: 'admin' | 'user'"] --> G