šŸŽ‰ DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Helm vs Kustomize vs Jsonnet: Which Config Tool Should You Use in 2026?

Helm, Kustomize, and Jsonnet all solve Kubernetes config management differently. Here's an honest comparison to help you pick the right one for your team.

DevOpsBoys3 min read
Share:Tweet

Every DevOps team eventually faces this: you need to manage Kubernetes configs across dev, staging, and prod environments — and plain YAML doesn't scale. The three main tools are Helm, Kustomize, and Jsonnet (via Tanka or raw).

Quick Summary

HelmKustomizeJsonnet
Template styleGo templatesPatch overlaysFunctional programming
Learning curveMediumLowHigh
Package managementYes (charts)NoNo
ArgoCD supportNativeNativeVia plugin
Best forDistributing reusable packagesEnvironment overlaysComplex, programmatic configs

Helm

Helm uses Go templates to generate Kubernetes manifests. You define a values.yaml and templates reference the values.

yaml
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.name }}
spec:
  replicas: {{ .Values.replicas }}
  template:
    spec:
      containers:
        - name: {{ .Values.name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          resources:
            limits:
              cpu: {{ .Values.resources.limits.cpu }}
              memory: {{ .Values.resources.limits.memory }}

Override values per environment:

bash
helm install myapp ./mychart -f values-prod.yaml

Best for:

  • Distributing software to others (Prometheus, ArgoCD, Cert-Manager all ship as Helm charts)
  • When you want package versioning and rollbacks
  • Teams that need a catalog of pre-built charts

Downsides:

  • Go templates get unreadable fast
  • Debugging template errors is painful
  • Not great for managing your OWN application across environments (use Kustomize for that)

Kustomize

Kustomize works with plain YAML and applies patches on top of a base. No templates, no new language.

my-app/
ā”œā”€ā”€ base/
│   ā”œā”€ā”€ deployment.yaml
│   ā”œā”€ā”€ service.yaml
│   └── kustomization.yaml
└── overlays/
    ā”œā”€ā”€ dev/
    │   └── kustomization.yaml
    └── prod/
        ā”œā”€ā”€ kustomization.yaml
        └── replicas-patch.yaml

Base kustomization:

yaml
# base/kustomization.yaml
resources:
  - deployment.yaml
  - service.yaml

Prod overlay:

yaml
# overlays/prod/kustomization.yaml
bases:
  - ../../base
patches:
  - path: replicas-patch.yaml
namePrefix: prod-
commonLabels:
  env: production

Replicas patch:

yaml
# overlays/prod/replicas-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 5

Build and apply:

bash
kubectl apply -k overlays/prod/
# or
kustomize build overlays/prod/ | kubectl apply -f -

Best for:

  • Managing your own application across multiple environments
  • Teams that want to stay in plain YAML
  • GitOps workflows with ArgoCD or FluxCD
  • Simple to moderate complexity configs

Downsides:

  • No loops or conditionals — if you need to create 10 similar resources, you're copy-pasting
  • Patches can get confusing with strategic merge vs JSON6902 patch types
  • No built-in package management

Jsonnet (via Grafana Tanka)

Jsonnet is a data templating language — think JSON + functions + variables. Tanka wraps it for Kubernetes.

jsonnet
// environments/prod/main.jsonnet
local k = import "k.libsonnet";
local app = import "../../lib/app.libsonnet";
 
{
  deployment: app.new(
    name="my-app",
    image="myrepo/myapp:v2.1.0",
    replicas=5,
    env="production",
  ),
}
jsonnet
// lib/app.libsonnet
local k = import "k.libsonnet";
 
{
  new(name, image, replicas=1, env="dev"):: {
    apiVersion: "apps/v1",
    kind: "Deployment",
    metadata: { name: name, labels: { env: env } },
    spec: {
      replicas: replicas,
      selector: { matchLabels: { app: name } },
      template: {
        metadata: { labels: { app: name } },
        spec: {
          containers: [{
            name: name,
            image: image,
          }],
        },
      },
    },
  },
}

Best for:

  • Teams managing hundreds of microservices with complex shared logic
  • Grafana's ecosystem (Tanka is used internally at Grafana Labs)
  • When you need real programming constructs: loops, conditionals, functions, imports

Downsides:

  • Steep learning curve — new language to learn
  • Smaller community than Helm/Kustomize
  • ArgoCD requires a plugin (not native)
  • Debugging requires tooling

When to Use Each

Use Helm when:

  • You're consuming third-party charts (always use Helm for this)
  • You're distributing your app as a package for others to install
  • You want chart versioning and helm rollback

Use Kustomize when:

  • You're managing your own application across 2-5 environments
  • You want to stay in plain YAML with minimal overhead
  • You're already using ArgoCD or FluxCD (both have native Kustomize support)

Use Jsonnet/Tanka when:

  • You have 50+ microservices with shared config patterns
  • Your team is comfortable with a new language
  • You need real programming logic in your configs

The Most Common Pattern in 2026

Most mature teams use Helm + Kustomize together:

  • Use Helm charts for third-party software (Prometheus, cert-manager, ingress-nginx)
  • Use Kustomize for your own application across environments
  • Store everything in Git and deploy with ArgoCD
ā”œā”€ā”€ infrastructure/
│   └── helm/           # third-party charts as HelmRelease objects
│       ā”œā”€ā”€ prometheus/
│       └── cert-manager/
└── applications/
    └── my-app/         # your app with Kustomize
        ā”œā”€ā”€ base/
        └── overlays/

This gives you the best of both: Helm's package ecosystem for external tools, and Kustomize's simplicity for your own code.

Resources:

šŸ”§

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments