Skip to main content
πŸŽ“ Claude Code Masterclass Learn AI-assisted development on Udemy β€” plus the companion book on Leanpub & Amazon. Start Learning
Kustomize vs Helm: Kubernetes Packaging Compared
Platform Engineering

Kustomize vs Helm 2026: When to Use Which (With Examples)

Kustomize vs Helm compared for Kubernetes. Patch-based overlays vs templating, GitOps workflows, learning curve, and when to use both together in production.

LB
Luca Berton
Β· 3 min read

The real question

Both Kustomize and Helm solve the same problem β€” managing Kubernetes manifests across environments β€” but they approach it from opposite philosophies. Kustomize patches existing YAML. Helm templates it. Neither is universally better. The right choice depends on your team, your application complexity, and your GitOps workflow.

After deploying both in production across dozens of projects, here is my honest comparison.

Feature comparison

FeatureKustomizeHelm
PhilosophyPatch-based overlaysTemplate engine + package manager
LanguagePure YAML (no templating)Go templates + YAML
Learning curveLow β€” it is just YAMLModerate β€” Go template syntax
Built into kubectlYes (kubectl apply -k)Separate binary
Package managementNoYes (charts, repos, OCI)
Dependency managementNoYes (subcharts)
ParameterizationStrategic merge patches, JSON patchesValues files, --set flags
RollbackNo native rollbackhelm rollback with revision history
Lifecycle hooksNoPre/post install, upgrade, delete hooks
Secret managementNo native supportHelm Secrets plugin, SOPS integration
Test frameworkNohelm test with test pods
GitOps compatibilityArgoCD + Flux nativeArgoCD + Flux native
Release trackingNo β€” statelessYes β€” Secrets-based release history

How Kustomize works

Kustomize starts with a base set of YAML manifests and applies layers of patches per environment:

β”œβ”€β”€ base/
β”‚   β”œβ”€β”€ kustomization.yaml
β”‚   β”œβ”€β”€ deployment.yaml
β”‚   β”œβ”€β”€ service.yaml
β”‚   └── configmap.yaml
β”œβ”€β”€ overlays/
β”‚   β”œβ”€β”€ dev/
β”‚   β”‚   β”œβ”€β”€ kustomization.yaml
β”‚   β”‚   └── replica-patch.yaml
β”‚   β”œβ”€β”€ staging/
β”‚   β”‚   β”œβ”€β”€ kustomization.yaml
β”‚   β”‚   └── resource-patch.yaml
β”‚   └── production/
β”‚       β”œβ”€β”€ kustomization.yaml
β”‚       β”œβ”€β”€ replica-patch.yaml
β”‚       └── hpa.yaml

base/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
  - configmap.yaml
commonLabels:
  app: my-api

overlays/production/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
  - hpa.yaml
patches:
  - path: replica-patch.yaml
    target:
      kind: Deployment
      name: my-api
namespace: production

overlays/production/replica-patch.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-api
spec:
  replicas: 5
  template:
    spec:
      containers:
        - name: my-api
          resources:
            requests:
              cpu: "500m"
              memory: "512Mi"
            limits:
              cpu: "2"
              memory: "2Gi"

Apply:

kubectl apply -k overlays/production/

What I like: You can read every file and understand exactly what YAML will be produced. No template conditionals, no {{ if }} blocks, no hidden logic. The output is deterministic and auditable.

How Helm works

Helm uses Go templates to generate manifests from a chart (a package of templates + default values):

templates/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-app.fullname" . }}
  labels:
    {{- include "my-app.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "my-app.selectorLabels" . | nindent 6 }}
  template:
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          {{- if .Values.livenessProbe.enabled }}
          livenessProbe:
            httpGet:
              path: {{ .Values.livenessProbe.path }}
              port: http
          {{- end }}

values-production.yaml:

replicaCount: 5
image:
  repository: registry.company.com/my-app
  tag: "v2.4.1"
resources:
  requests:
    cpu: "500m"
    memory: "512Mi"
  limits:
    cpu: "2"
    memory: "2Gi"
livenessProbe:
  enabled: true
  path: /healthz

Deploy:

helm upgrade --install my-app ./chart \
  -f values-production.yaml \
  --namespace production \
  --create-namespace

What I like: One chart can serve dozens of environments with just a values file. Helm charts are shareable, versionable, and composable with subcharts. The ecosystem (Artifact Hub, Bitnami, vendor charts) saves enormous time.

When to use Kustomize

Simple applications with few configuration variants. If your app has 3-5 manifests and the only difference between environments is replica count, resource limits, and namespace β€” Kustomize is the right tool. Adding Helm for this is over-engineering.

Teams that hate templating. Some engineers find Go template syntax in YAML files genuinely painful. Kustomize’s β€œit is just YAML” philosophy avoids that entirely.

kubectl-native workflows. No extra binary to install, no Tiller (thankfully gone), no chart packaging. kubectl apply -k works everywhere.

Compliance environments. When auditors want to see exactly what will be deployed, Kustomize’s deterministic output is easier to review than Helm’s template rendering.

When to use Helm

Complex applications with many knobs. If your deployment has 20+ configurable parameters, conditional resources, and multiple deployment modes β€” Helm’s templating power is worth the complexity.

Sharing across teams or publicly. If you want other teams or the community to use your deployment, Helm charts with a values.yaml interface is the standard packaging format.

You need rollback and release history. Helm tracks every release as a Kubernetes Secret. helm rollback my-app 3 is one command. With Kustomize, you need GitOps or manual kubectl apply of a previous commit.

Dependency management. Your app needs Redis, PostgreSQL, and an ingress controller? Helm subcharts handle this. Kustomize has no native dependency concept.

Use both together (the 2026 pattern)

The most pragmatic teams in 2026 use both:

  1. Helm for third-party applications (Prometheus, Grafana, cert-manager, NGINX Ingress) β€” use the vendor’s chart as-is with custom values
  2. Kustomize for your own applications β€” simpler, more readable, no template maintenance
  3. Helm template + Kustomize overlay for advanced cases β€” render Helm charts into static YAML, then apply Kustomize patches
# Render Helm chart to static manifests
helm template prometheus prometheus-community/kube-prometheus-stack \
  -f base-values.yaml > base/prometheus.yaml

# Apply environment-specific patches with Kustomize
kubectl apply -k overlays/production/

This pattern gives you Helm’s ecosystem for third-party software and Kustomize’s simplicity for your own code.

GitOps compatibility

Both work well with ArgoCD and Flux:

ArgoCD with Kustomize:

apiVersion: argoproj.io/v1alpha1
kind: Application
spec:
  source:
    repoURL: https://github.com/company/k8s-config
    path: overlays/production

ArgoCD with Helm:

apiVersion: argoproj.io/v1alpha1
kind: Application
spec:
  source:
    repoURL: https://charts.company.com
    chart: my-app
    targetRevision: "2.4.1"
    helm:
      valueFiles:
        - values-production.yaml

Flux with Kustomize:

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
spec:
  sourceRef:
    kind: GitRepository
    name: k8s-config
  path: ./overlays/production

My recommendation

Start with Kustomize for your own applications. Switch to Helm only when you hit one of these:

  • You need to package and share the deployment
  • You need 10+ configurable parameters per environment
  • You need lifecycle hooks or rollback
  • You are deploying a third-party application that ships a Helm chart

Most teams end up using both. That is fine. They solve different problems.

Free 30-min AI & Cloud consultation

Book Now