Skip to content

Helm vs Kustomize

Helm and Kustomize are often framed as alternatives, but they divide the work by concern rather than competing for the same job. The question is not which tool to use, but what kind of resource you’re deploying and who wrote it.

Who wrote it? Start here.

  • Someone else (open source chart, vendor chart): use helm install. You get the community’s operational expertise, upgrade orchestration, and built-in rollback.
  • You wrote it: use Kustomize, unless you’re packaging it for other teams to install — in which case, write a Helm chart.

For your own apps, how similar are they?

  • Structurally identical, different config (same Deployment shape, different domain and env vars): one Helm chart, one values file per instance. This project uses charts/website/ with values/website-a.yaml through values/website-l.yaml to deploy twelve sites from a single chart.
  • Mostly similar, some structural differences (one site needs a sidecar, another has a CronJob): Kustomize base plus per-site overlays.
  • Completely different apps: separate charts or separate bases. Never force shared structure just because two apps are both websites.

For cluster policies (RBAC, NetworkPolicy, namespaces, quotas): always Kustomize. Plain YAML is auditable, diffs cleanly in pull requests, and needs no templating engine.

This project splits the cluster across three buckets:

helm install — third-party stateful infrastructure

Postgres, ingress-nginx, cert-manager. Helm is the right tool here because it maintains an application registry, tracks installed versions, supports dependency declarations, and can roll back a broken upgrade as a unit. When you run helm template instead of helm install for these, you give up all of that. A Postgres upgrade gone wrong with helm install is a helm rollback away from recovery. The same upgrade applied with kubectl apply leaves you untangling state by hand.

helm template rendered to static YAML — third-party stateless charts

CRD bundles, one-time bootstrap jobs, charts you want to fork and own. Render the chart to plain YAML with helm template, commit it to git, and apply it with kubectl apply. You get the chart author’s manifest expertise and full git visibility. The tradeoff: Helm hooks only run at specific lifecycle events, and helm template dumps all of them into the output — including uninstall batch jobs you probably didn’t want. Review the rendered output before committing.

Kustomize — everything you own

Your SolidStart apps, API services, custom CronJobs, and all cluster policies. infrastructure/base/ holds namespaces, RBAC, NetworkPolicies, and ResourceQuotas. infrastructure/overlays/doks/ and infrastructure/overlays/k0s/ apply the per-cluster differences. kubectl apply -k is the only deploy command you need.

Avoid Kustomize’s helmCharts integration

Section titled “Avoid Kustomize’s helmCharts integration”

Kustomize has a helmCharts generator field and an --enable-helm flag. Don’t use them in production. The official Kustomize docs describe depending on remote chart configurations as “irresponsible” and acknowledge the flag is “useless as a reminder, since annoying things are immediately scripted away and forgotten.”

The concrete bugs are worse than the philosophy:

  • Changing the chart version in kustomization.yaml doesn’t pull the new version — Kustomize reuses the cached chart and silently deploys the wrong one.
  • Charts without a values.yaml crash Kustomize, even though helm template handles them fine.
  • Kustomize can’t replace or merge ConfigMaps generated by the Helm generator.
  • valuesFile doesn’t support merging multiple values files, so each environment needs a full values file rather than just overrides.
  • When both a values file and a Kustomize patch target the same field, the precedence is undefined.

The hybrid that actually works: render with helm template, commit the YAML, patch with Kustomize overlays on top. You get the chart’s expertise and Kustomize’s composability with none of the integration bugs.

| Resource | Tool | Command | | ------------------------------------------ | ----------------------------- | ---------------------------------------------------------------- | ------------------- | | Third-party stateful app (Postgres, Redis) | helm install | helm install pg bitnami/postgresql -f values.yaml | | Third-party stateless chart (CRD bundle) | helm template → static YAML | helm template ... | kubectl apply -f - | | Your apps (12 websites, same structure) | Helm chart + values files | helm install website-a charts/website -f values/website-a.yaml | | Your apps (structural differences) | Kustomize base + overlays | kubectl apply -k overlays/website-a/ | | Cluster policy (RBAC, namespaces) | Kustomize | kubectl apply -k infrastructure/overlays/doks/ |