KBkilterKB
userdev

How kilter uses Helm

Helm is the Kubernetes package manager: a chart is a bundle of templated manifests plus default values, and installing one into a cluster creates a release that can be upgraded or rolled back as a unit. Kilter uses Helm in both dev and production — but in both cases, kilter runs it for you. You never install helm or write a chart.

Dev: charts render the service catalog

Every backing service in the catalog — postgres, redis, temporal, ory, signoz, and the rest — is a Helm chart. When you run kilter add redis (or auto-detection finds ioredis in your dependencies), kilter:

  1. Adds the service to kilter.yaml.
  2. Renders its chart with project-specific values — your namespace, your deterministic ports, sane resource defaults.
  3. Hands the result to Tilt, which applies it to your cluster.

That's why a one-line services: entry produces a full StatefulSet-plus-Service-plus-config stack: the chart carries the operational knowledge, and kilter fills in the per-project values.

Changing chart values requires a release upgrade — that's why the update table in Tilt says kilter up for Helm value changes, not kilter restart.

Production: the kilter-app chart

Production uses the same idea, one level up. kilter deploy doesn't run Helm on your machine at all:

  1. The CLI builds your image locally and pushes it to the platform registry.
  2. It POSTs to kilter-server, which upserts a KilterApp custom resource.
  3. The in-cluster operator renders the kilter-app chart — Deployment, Service, route on the cluster Gateway, secrets wiring — and commits the output to the cluster's flux repo.
  4. Flux applies the commit; your app goes live at <app>.<cluster-domain>.

No kubectl, no helm, no flux on your machine. See Production routing for how the URL works.

The eject pattern: customizing rendered artifacts

Rendered artifacts (manifests, Tiltfile, Dockerfiles) live outside your repo at ~/.cache/kilter/<name>/, regenerated as needed. When the defaults aren't enough — you need to tweak resource limits, add a sidecar, adjust a sync rule — eject:

kilter eject --list      # what can be ejected
kilter eject <thing>     # copy it into your project

Once ejected, the artifact belongs to you: kilter won't overwrite it, and your edits persist across kilter up and re-renders.

Eject narrowly

Ejected files stop receiving kilter's updates — improved defaults and fixes no longer flow to them. Eject only the artifact you actually need to change, not everything, and consider whether an inline override in kilter.yaml (image, port, env) gets you there without ejecting at all.

kilter render re-renders whatever is not ejected, which is the way back if generated artifacts drift or you delete an ejected copy to return to defaults.