Skip to content

Multi-app layout

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.

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
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" }
}
}
  • namespace — injected into every block in every sub-project that doesn’t already have one
  • service_account — injected into every deployment/cronjob that doesn’t already have one
  • ingress_defaults — applied to every ingress
  • configmaps.kdef / secrets.kdef — parsed once at the root, visible from every sub-project
Terminal window
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.

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.

See Reference → Block types → root.kdef.