31.6 Kustomize vs Helm: When to Use Each
Alright, let’s settle this. The “Kustomize vs. Helm” debate is the tech equivalent of “Vim vs. Emacs” or “Tabs vs. Spaces”—it generates more heat than light because people treat it like a religious war. It’s not. They are different tools designed for different jobs, and the only wrong choice is using one when you should have used the other. Let’s break it down so you can stop arguing and start deploying.
The Core Philosophy: Overlays vs. Charts
Think of it this way: Helm is a package manager for Kubernetes, and Kustomize is a configuration patcher. This distinction is everything.
Helm’s mental model is inspired by apt or yum. You find a “chart” for, say, Redis. This chart is a templatized package that knows how to deploy Redis. You provide a values.yaml file to fill in the template’s blanks (e.g., password: "supersecret", replicaCount: 3), and Helm renders all the Kubernetes YAML manifests for you and shoots them off to the API server. It’s fantastic for off-the-shelf software where you’re a consumer.
Kustomize takes the opposite approach. Its entire ethos is that you already have plain, vanilla YAML files (maybe you wrote them yourself, maybe you used kubectl create deployment nginx --dry-run=client -o yaml). Kustomize says, “Don’t template these; patch them.” You have a base—your canonical, pristine set of manifests. Then you create overlays (e.g., for dev, staging, production) that kustomize this base by patching in environment-specific changes: adding a sidecar, changing the number of replicas, applying labels, etc.
# base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
# overlays/prod/kustomization.yaml
resources:
- ../../base
patchesStrategicMerge:
- increase_replicas.yaml
- add_ingress.yaml
Helm creates YAML from a template and your values. Kustomize takes existing YAML and strategically merges changes onto it.
When to Reach for Helm
Use Helm when you need to install and manage third-party applications whose manifests you don’t want to write or maintain. Think complex stuff like Istio, Vault, or Grafana. The chart maintainer handles the mind-boggling complexity of configuring all those objects, and you just provide a simple values file. This is its superpower.
It’s also useful if you’re building a complex application for others to consume. If your app has 10 microservices, a database, a cache, and a message queue, writing a Helm chart is a sane way to let users deploy the whole stack with one command (helm install my-big-app ./my-chart).
The big gotcha? Helm’s templating language is… an acquired taste. It’s a fork of Go templates, and while powerful, it can become a write-only language of terrifying complexity. Debugging a .tpl file with deeply nested {{ if .Values.global.database.enabled }} statements is a special kind of hell. Also, helm upgrade can be a bit of a black box; you’re never quite sure what it’s going to change until you run it with --dry-run.
When Kustomize Shines
Use Kustomize when you are managing your own configuration. You wrote the manifests for your app team’s services, and you just need to promote the same basic application through different environments with slight tweaks. It’s the king of GitOps workflows.
Its beauty is in its simplicity and transparency. There are no templates, just patches. What you see is what you get. You can kubectl kustomize overlays/prod/ and see exactly what YAML will be applied to your cluster. This makes it incredibly easy to reason about and debug.
# overlays/prod/increase_replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 5 # Because prod needs to handle the load
The pitfall? It can feel a bit manual. If you have 20 microservices that all need the same new environment variable, you’ll be writing 20 patches. This is where people scream, “See! You need Helm templates!” But often, a little cleverness with Kustomize’s generator features or other GitOps tools (like ArgoCD ApplicationSets) can solve this more cleanly.
The Real Answer: Use Both, You Maniac
Here’s the secret the manuals don’t tell you: you can and should use them together. This isn’t a cop-out; it’s the professional way to handle real-world complexity.
Let Helm do what it’s good at: managing the complex third-party infrastructure. Then let Kustomize manage your application’s deployment on top of it.
# Your app's kustomization.yaml
resources:
- github.com/helm/charts/stable/redis-ha?ref=redis-ha-4.4.2 # Helm as a base!
- ../base/my-app-deployment.yaml
- ../base/my-app-service.yaml
patchesStrategicMerge:
- patch_redis_with_my_config.yaml
- add_sidecar_to_my_app.yaml
You used Helm to deploy the Redis cluster. Beautiful. You didn’t have to write that manifest. But you used Kustomize to inject your specific Redis configuration and to patch your application deployment with the sidecar that needs to talk to it. Genius. You’ve leveraged the strengths of both tools while avoiding their individual weaknesses. Now that’s knowing your stuff.