Skip to content

Why kdef

You have two options for templating Kubernetes manifests, and neither feels right.

Kustomize has no variables and no loops. You end up maintaining a tree of base/ and overlays/, duplicating blocks of YAML, and writing strategic-merge patches that only make sense if you can hold the whole tree in your head.

Helm has variables and loops, but it does them with Go templates wrapped around YAML. The result is a language where a missing space or a forgotten toYaml | nindent 4 produces an invalid manifest at deploy time. You can’t read a Helm chart. You run helm template and read the output.

kdef is what sits between them.

  • A language — HCL syntax. Typed variables. Native for loops. Conditionals that aren’t strings.
  • A compilerkdef render produces plain Kubernetes YAML. Nothing hidden. kdef diff shows exactly what will change in the cluster.
  • A deployment toolkdef apply does server-side apply. kdef import turns a live namespace into .kdef files.

kdef is purpose-built for Kubernetes: a deployment block generates a Deployment, Service, Ingress, Certificate, and HPA. You write your app in one block instead of five.

variable "environment" {
type = "enum[staging, production]"
default = "staging"
}
variable "replicas" {
type = "number"
default = 1
}

Typo in the value? Caught at kdef validate, not by your paging on-call.

for "tenant" "var.tenants" {
deployment "booking" {
name = "booking-${tenant.name}"
container "booking" {
image = image("booking")
env { TENANT_ID = tenant.name }
}
ingress {
host = tenant.domain
tls = true
}
}
}

No range blocks, no nindent, no escaping. Give it a JSON values file and you get one Deployment + Service + Ingress per tenant.

environments/production.kdef
use_vars {
environment = "production"
image_tag = "v2.4.1"
}
override "app" "api" {
scale { replicas = 3 }
}

One file per environment. No overlays/ trees.

sealedsecret "db-credentials" {
data = {
DATABASE_URL = "AgBy3i4OJSWK+PiTySYZZA9rO..."
}
}

kdef seal --secret db-credentials --key DATABASE_URL --value "$PLAINTEXT" outputs the encrypted blob. Paste it in. Commit it. Safe.

Terminal window
kdef import --namespace my-app --output-dir k8s/

Turns every Deployment, Service, Ingress, ConfigMap, Secret, CronJob in the namespace into idiomatic .kdef files. Migrate incrementally.

  • It isn’t a general-purpose config language. If you need CUE’s constraint system or KCL’s type system, use those.
  • It isn’t a drop-in Helm replacement for every chart on Artifact Hub — if you pull charts from vendors, you’ll keep using Helm for those.
  • It isn’t trying to be fancy. HCL, Go, plain YAML output. That’s the stack.
  • Install — binary, Go install, or Linux packages
  • Quickstart — import a live namespace, render, diff, apply
  • Comparison — kdef vs Kustomize, Helm, CUE, KCL, Pkl