Multi-app layout
Ship several apps together with root.kdef: shared namespaces, service accounts, and ingress defaults.
When a repository ships several apps together (api + web + worker, or a full stack deployed as a unit), the root.kdef file at the top lets you declare shared state once and have every sub-project pick it up.
Repository layout
repo/
├── root.kdef ← namespaces, service accounts, app list
├── vars.kdef ← shared variables, ingress defaults
├── images.kdef ← shared image registry
├── configmaps.kdef ← shared configmaps (parsed once)
├── secrets.kdef ← shared sealed secrets (parsed once)
├── api/
│ ├── vars.kdef ← overrides for api only
│ └── app.kdef ← deployment "api"
├── web/
│ └── app.kdef ← deployment "web"
├── worker/
│ └── app.kdef ← deployment "worker"
└── environments/
├── staging.kdef
└── production.kdef
root.kdef
# root.kdef
namespaces = ["production", "staging"]
service_account "default" {
image_pull_secrets = ["regcred"]
}
ingress_defaults {
tls = true
issuer = "letsencrypt-production"
annotations = {
"nginx.ingress.kubernetes.io" = {
"force-ssl-redirect" = "true"
}
}
}
deployments = {
"api" = {
path = "api"
namespace = "production"
service_account = "default"
}
"web" = {
path = "web"
namespace = "production"
service_account = "default"
}
"worker" = {
path = "worker"
namespace = "production"
}
# Same api, different namespace, different vars: staged copy
"api-staging" = {
path = "api"
namespace = "staging"
service_account = "default"
env = "staging"
set = { "replicas" = "1" }
}
}
What you don't have to repeat
namespace: injected into every block in every sub-project that doesn't already have oneservice_account: injected into every deployment/cronjob that doesn't already have oneingress_defaults: applied to every ingressconfigmaps.kdef/secrets.kdef: parsed once at the root, visible from every sub-project
Running it
kdef validate --dir repo/ # validates all apps
kdef render --dir repo/ # renders all apps
kdef diff --dir repo/ --env staging # diffs all apps
kdef apply --dir repo/ --env prod # applies all apps
One command, every app. No for-loops in your deploy script.
Variable scoping
Variables follow the directory tree. A vars.kdef at the root is visible everywhere; a vars.kdef inside api/ is only visible to api/**, and overrides the root on name collision.
repo/
├── vars.kdef # { environment = "staging" }: default for everyone
└── api/
└── vars.kdef # { replicas = 3 }: only api sees this
Same for images {} blocks: a deeper images.kdef overrides a shallower one for that sub-tree.