Articles

Helm vs Kustomize for Kubernetes Config

Helm templates and packages Kubernetes manifests with a templating language; Kustomize patches plain YAML declaratively, with no templates at all.

Chisato Chisato · · 4 min read
Stylized Kubernetes wheel logo on a dark background

Helm and Kustomize solve the same underlying problem — managing Kubernetes YAML across multiple environments without duplicating entire manifest files — but they take opposite approaches. Helm treats manifests as templates filled in with variables and packages them into versioned, shareable units called charts. Kustomize treats manifests as plain, valid YAML and layers declarative patches on top, with no templating language involved at all.

Helm: templates and packages

A Helm chart is a directory of templated YAML files plus a values.yaml file supplying the variables that fill them in. Deploying a chart means rendering the templates with a given set of values and applying the result:

# templates/deployment.yaml
spec:
  replicas: {{ .Values.replicaCount }}
  containers:
    - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"

Different environments — staging, production, a customer’s own cluster — get different values.yaml overrides, but share the same underlying templates. Charts can be versioned, published to repositories, and installed with a single helm install command, which is why Helm became the default way to distribute complex, multi-resource applications (an ingress controller, a database operator, a full observability stack) as a single reusable package. Helm also tracks release history, so helm rollback can revert a release to a previous rendered state, and it manages the full lifecycle of ConfigMaps and Secrets or CRDs that a chart defines, alongside the core Pods, Deployments, and Services it deploys.

The cost is the templating language itself — Go templates embedded in YAML, which are not YAML until rendered. Debugging a broken chart often means running helm template to see the rendered output before you can tell whether the problem is in the template logic or the underlying manifest.

Kustomize: patches on plain YAML

Kustomize takes a different position: manifests should stay valid, plain YAML, with no template syntax and no variables. Instead of filling in placeholders, you write a base set of manifests and then define overlays that patch specific fields for each environment:

# overlays/production/kustomization.yaml
resources:
  - ../../base
patches:
  - target:
      kind: Deployment
      name: web
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 5

Because the base manifests are always valid YAML on their own, they can be read, edited, and applied directly with kubectl apply -k without any rendering step. Kustomize ships built into kubectl itself, so no separate tool installation is required to use the basic overlay pattern. The tradeoff is that Kustomize has no packaging or distribution model comparable to Helm charts — there’s no equivalent of helm install some-chart pulling in an entire pre-built application with one command, and no built-in release history or rollback tracking the way Helm maintains it.

Comparing the two directly

HelmKustomize
Base formatGo templates, not valid YAML until renderedPlain, valid YAML throughout
Environment differencesvalues.yaml overridesOverlay patches (JSON patch or strategic merge)
Packaging/distributionVersioned charts, chart repositoriesNo native packaging — overlays reference base directories
Built into kubectlNo — separate CLIYes (kubectl apply -k)
Release history/rollbackBuilt in (helm rollback)Not built in — relies on external tooling or GitOps history
Best fitDistributing reusable, third-party, or complex multi-resource appsManaging environment-specific variants of your own manifests

They aren’t mutually exclusive

A common pattern combines both: use Helm to install third-party components that are only distributed as charts — an ingress controller or a monitoring stack, for instance — while using Kustomize (or helm template piped into a Kustomize overlay) to manage your own application manifests, where plain YAML and patches are easier to review in a pull request than templated files. Kustomize can even post-process the output of helm template, letting teams get Helm’s packaging for dependencies without adopting Go templates for their own manifests.

Both tools are commonly wired into a GitOps workflow, where a reconciliation controller watches a Git repository and applies whatever the rendered manifests describe — the choice of Helm or Kustomize mostly affects how that repository is structured, not whether GitOps itself works. Compared to a general-purpose infrastructure tool like Terraform, both Helm and Kustomize operate specifically on Kubernetes manifests rather than cloud infrastructure broadly, which is why they’re often used alongside Terraform rather than instead of it — Terraform provisions the cluster, Helm or Kustomize configures what runs inside it.

Picking one

If you’re distributing an application for other people to install into clusters you don’t control, or you need versioned releases with rollback, Helm’s packaging model is hard to replace. If you’re managing your own manifests across a handful of environments and want to review diffs as plain YAML in a pull request without a templating layer in between, Kustomize’s patch-based approach tends to be easier to reason about and easier to review. Many teams end up using both, for different halves of the same cluster.

The takeaway

Helm packages templated manifests into versioned, distributable charts with built-in release tracking; Kustomize patches plain, valid YAML through layered overlays with no templating language at all. Helm wins for distributing reusable applications and needing rollback history; Kustomize wins for keeping your own manifests reviewable as ordinary YAML. Neither replaces the other outright, and plenty of clusters run both side by side.

Chisato Chisato · · 4 min read

Kubernetes Init Containers Explained

Init containers run to completion before a pod's main containers start, making them the standard way to handle setup steps and startup ordering.

#Kubernetes #DevOps #Cloud