Kubernetes Kustomize: Environment-Specific Configuration (2026)
1. Kustomize vs Helm: Overlay vs Template Engine
When managing Kubernetes configurations across multiple environments, two tools dominate the landscape: Kustomize and Helm. While both solve the same core problem — avoiding copy-paste duplication of YAML — they take fundamentally different approaches.
Helm uses a template engine: your Kubernetes manifests are Go templates with placeholders, and Helm renders them by injecting values. Kustomize, on the other hand, uses an overlay approach: you write plain, valid Kubernetes YAML as a base, then apply patches and transformations on top. No templating syntax, no curly braces, no rendering step required.
| Feature | Kustomize | Helm |
|---|---|---|
| YAML validity | Always valid YAML | Template syntax breaks native YAML tools |
| Learning curve | Low — patch-based | Medium — Go template DSL |
| Package distribution | No built-in packaging | Chart repositories, OCI registries |
| Environment overrides | Native (overlays) | values.yaml per environment |
| kubectl integration | Built in since kubectl 1.14 | Separate CLI required |
| Secret management | Basic generators; use external tools | Basic values; use external tools |
| Rollback | Manual (git revert) | Built-in helm rollback |
| Best for | In-house apps, GitOps | Third-party chart distribution |
In 2026, many teams use both: Helm for third-party dependencies, Kustomize for their own application manifests. Kustomize can even wrap Helm charts via the helmCharts field, giving you the best of both worlds.
See our Kubernetes Helm Guide for a deep dive into the Helm workflow.
2. Project Structure: Base and Overlays
The canonical Kustomize layout separates base manifests (shared across all environments) from overlays (environment-specific customizations). Each directory contains a kustomization.yaml file that acts as the entry point.
my-app/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── configmap.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ └── patch-replicas.yaml
├── staging/
│ ├── kustomization.yaml
│ ├── patch-replicas.yaml
│ └── patch-resources.yaml
└── prod/
├── kustomization.yaml
├── patch-replicas.yaml
├── patch-resources.yaml
└── patch-hpa.yaml
The base/ directory contains your canonical Kubernetes manifests — the same YAML you would apply to any cluster. Each overlay directory references the base and adds only what differs: more replicas in prod, smaller resource limits in dev, different image tags per environment.
This structure maps cleanly to a GitOps repository. Your CI pipeline builds and tags a new image; your CD tool (ArgoCD, Flux) reads the overlay for the target environment and applies it. See our ArgoCD GitOps guide for the full pipeline.
base/ manifests runnable on their own. They should represent a minimal but valid deployment — typically with conservative resource requests and a single replica. Overlays only add or change values.
3. Base kustomization.yaml
The base kustomization.yaml lists the resources to include and applies transformations common to all environments such as labels and namespace defaults.
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
commonLabels:
app: my-app
team: platform
managed-by: kustomize
namespace: my-app
images:
- name: my-app
newName: registry.example.com/my-app
newTag: latest
Key fields in the base:
- resources — list of YAML files (or remote URLs / other kustomization directories) to include.
- commonLabels — labels applied to every resource and selector. Use with care: changing these is a breaking change for existing deployments.
- namespace — sets the namespace on all namespaced resources.
- images — override image names and tags without touching the deployment YAML.
The base deployment.yaml uses the plain image name that the images transformer will rewrite:
# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app:latest
ports:
- containerPort: 8080
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
For managing application configuration data, review our article on Kubernetes ConfigMaps and Secrets.
4. Overlay kustomization.yaml
Each overlay's kustomization.yaml references the base and declares its patches. The dev overlay is the simplest — it typically just bumps replicas to 1 and uses a feature-branch image tag.
# overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namePrefix: dev-
images:
- name: my-app
newName: registry.example.com/my-app
newTag: dev-latest
patches:
- path: patch-replicas.yaml
target:
kind: Deployment
name: my-app
commonLabels:
environment: dev
# overlays/dev/patch-replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
The production overlay is more involved — it increases replicas, raises resource limits, and may add an HPA patch:
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
- hpa.yaml
images:
- name: my-app
newName: registry.example.com/my-app
newTag: v2.4.1
patches:
- path: patch-replicas.yaml
target:
kind: Deployment
name: my-app
- path: patch-resources.yaml
target:
kind: Deployment
name: my-app
commonLabels:
environment: prod
5. Strategic Merge Patches
A strategic merge patch is the most natural patching style for Kubernetes users. You write a partial Kubernetes manifest that mirrors the structure of the resource you want to change, and Kustomize merges it intelligently — lists of named items (like containers) are merged by name, not replaced wholesale.
# overlays/prod/patch-resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: my-app
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 1Gi
Because Kubernetes understands that containers is a list of named objects, the patch locates the container named my-app and merges only the resources field — it does not replace other container fields like ports or env.
You can patch environment variables the same way:
# overlays/staging/patch-env.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: my-app
env:
- name: APP_ENV
value: staging
- name: LOG_LEVEL
value: debug
- name: DB_POOL_SIZE
value: "5"
6. JSON 6902 Patches
RFC 6902 JSON Patch gives you precise surgical control: add, replace, or remove any field or array element by path. It is especially useful for removing items from arrays or targeting specific array indices.
# overlays/prod/patch-remove-debug.yaml
- op: remove
path: /spec/template/spec/containers/0/env/2
Reference this in kustomization.yaml using the inline patch syntax (Kustomize v4+):
# overlays/prod/kustomization.yaml (patch section)
patches:
- target:
kind: Deployment
name: my-app
patch: |-
- op: replace
path: /spec/replicas
value: 5
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: JAVA_OPTS
value: "-Xms512m -Xmx2g -XX:+UseG1GC"
- op: replace
path: /spec/template/spec/containers/0/readinessProbe/initialDelaySeconds
value: 30
Common JSON 6902 operations:
add— insert a value. Use/-to append to an array.replace— replace an existing value (path must exist).remove— delete a field or array element.move— move a value from one path to another.copy— copy a value to a new path.
/containers/0 will break if the containers list order changes. Prefer strategic merge patches for named-list operations; use JSON 6902 only when strategic merge cannot express the change.
7. ConfigMap Generator
Kustomize's ConfigMap generator creates ConfigMaps from files, literals, or .env files — and automatically appends a content hash to the ConfigMap name. This hash-based naming forces a rolling update whenever the config changes, eliminating the "my pods still have the old config" problem.
# base/kustomization.yaml (configMapGenerator section)
configMapGenerator:
- name: app-config
literals:
- APP_NAME=my-app
- APP_VERSION=2.4.1
- FEATURE_FLAGS=cache,tracing
- name: app-properties
files:
- configs/application.properties
- configs/logback.xml
- name: app-env
envs:
- configs/app.env
Kustomize generates a ConfigMap named something like app-config-7bgh9k2m4t. It also automatically updates all Deployment, StatefulSet, and DaemonSet references to use the new hashed name — so your pods roll out with the new config automatically.
To disable hash suffix (e.g., when the ConfigMap is referenced by an external controller), use the options field:
# base/kustomization.yaml
configMapGenerator:
- name: stable-config
literals:
- KEY=value
options:
disableNameSuffixHash: true
labels:
config-type: stable
8. Secret Generator
The Secret generator works identically to the ConfigMap generator but produces Secret objects with base64-encoded values. Like ConfigMaps, generated secrets get a hash suffix that triggers rolling updates.
# overlays/prod/kustomization.yaml (secretGenerator section)
secretGenerator:
- name: db-credentials
literals:
- DB_USER=produser
- DB_PASSWORD=supersecretpassword
type: Opaque
- name: tls-certs
files:
- tls.crt=certs/prod.crt
- tls.key=certs/prod.key
type: kubernetes.io/tls
See our Kubernetes Security Best Practices and RBAC Security articles for the full secrets management picture.
9. Image Transformer
The image transformer is one of Kustomize's most-used features in CI/CD pipelines. It lets each overlay declare a specific image tag without patching the Deployment YAML directly. Your CI pipeline can even update the tag programmatically using the kustomize edit set image command.
# overlays/prod/kustomization.yaml
images:
- name: my-app
newName: registry.example.com/my-app
newTag: v2.4.1
- name: sidecar-proxy
newName: registry.example.com/envoy-proxy
newTag: v1.29.3
digest: sha256:abc123def456...
Fields explained:
- name — the image name to match in any container spec across all resources.
- newName — optionally replace the registry/repository path.
- newTag — the tag to use (e.g., a Git SHA, semver tag, or
latest). - digest — pin to an immutable digest instead of a mutable tag for production security.
In a GitOps pipeline, your CI job updates the overlay's image tag automatically:
# In your CI script (bash)
cd overlays/prod
kustomize edit set image my-app=registry.example.com/my-app:${GIT_SHA}
git commit -am "chore: bump my-app image to ${GIT_SHA}"
git push
ArgoCD or Flux then detects the Git change and applies the updated overlay to the cluster. See our ArgoCD GitOps guide for the complete pipeline setup.
For resource management patterns around image rollouts, see Kubernetes Resource Management.
10. namePrefix and nameSuffix
namePrefix and nameSuffix prepend or append a string to the names of all resources in a kustomization. This is useful when deploying the same application multiple times into the same namespace — for example, a canary deployment alongside the stable version, or deploying per-team instances of a shared service.
# overlays/canary/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namePrefix: canary-
images:
- name: my-app
newName: registry.example.com/my-app
newTag: v2.5.0-rc1
patches:
- target:
kind: Deployment
name: canary-my-app
patch: |-
- op: replace
path: /spec/replicas
value: 2
After applying this overlay, your cluster will have both my-app (stable) and canary-my-app deployments, each with their own Service and ConfigMap named accordingly. Kustomize automatically updates all cross-references so that the canary Service selector still matches the canary Deployment pods.
namePrefix and nameSuffix are applied after commonLabels. When writing patches, use the post-prefix name (e.g., canary-my-app, not my-app) in the patch target.
11. Kustomize Components: Reusable Cross-Cutting Overlays
Introduced in Kustomize v3.7, Components solve a common problem: you have a feature (e.g., Prometheus metrics scraping, external secrets, network policies) that you want to enable in some environments but not others. Components let you package that feature as a reusable unit and opt into it per overlay.
# components/monitoring/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
patches:
- patch: |-
- op: add
path: /spec/template/metadata/annotations
value:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/actuator/prometheus"
target:
kind: Deployment
resources:
- servicemonitor.yaml
# components/network-policy/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
resources:
- network-policy.yaml
Enable components selectively in each overlay:
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
components:
- ../../components/monitoring
- ../../components/network-policy
images:
- name: my-app
newName: registry.example.com/my-app
newTag: v2.4.1
# overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
# No components in dev — no monitoring or network policy overhead
images:
- name: my-app
newName: registry.example.com/my-app
newTag: dev-latest
This is far cleaner than duplicating patch files across overlays or using conditional logic. For monitoring setup details, see our Kubernetes Monitoring with Prometheus article.
12. kubectl kustomize vs the kustomize CLI
Kustomize is built into kubectl since version 1.14, so most teams use it without installing anything extra. However, the bundled version lags behind the standalone kustomize CLI by several releases. In 2026, kubectl 1.30+ bundles Kustomize v5.x, which supports all features covered in this article.
Key commands:
# Preview what will be applied (dry run — outputs YAML to stdout)
kubectl kustomize overlays/prod
# Apply an overlay directly
kubectl apply -k overlays/prod
# Delete resources defined by an overlay
kubectl delete -k overlays/prod
# Using the standalone kustomize CLI
kustomize build overlays/prod | kubectl apply -f -
# Diff against the live cluster (requires kubectl diff)
kubectl diff -k overlays/prod
# Update image tag in an overlay (standalone CLI only)
cd overlays/prod && kustomize edit set image my-app=registry.example.com/my-app:v2.5.0
kubectl apply -k for day-to-day operations and in CI pipelines. Install the standalone kustomize CLI when you need the kustomize edit commands for automated image tag updates.
Install the standalone CLI:
# Linux/macOS
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
# macOS with Homebrew
brew install kustomize
# Windows with Chocolatey
choco install kustomize
To learn more about core Kubernetes deployment operations, see our Kubernetes Deployments guide.
13. Integrating Kustomize with ArgoCD
ArgoCD has first-class native support for Kustomize. When you point an ArgoCD Application at a directory containing a kustomization.yaml, ArgoCD automatically runs kustomize build and applies the output. No additional configuration is needed.
# argocd-app-prod.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app-prod
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/my-app-gitops
targetRevision: main
path: overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: my-app-prod
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
You can also pass Kustomize-specific options in the ArgoCD Application:
# Advanced Kustomize options in ArgoCD Application
spec:
source:
repoURL: https://github.com/my-org/my-app-gitops
targetRevision: main
path: overlays/prod
kustomize:
version: v5.3.0 # Pin kustomize version
images:
- my-app=registry.example.com/my-app:v2.4.1 # Override image at sync time
commonLabels:
gitops-managed: "true"
namePrefix: prod- # Additional prefix
With automated sync and self-heal enabled, ArgoCD will automatically apply any overlay changes pushed to the Git repository — completing the GitOps loop. Review the full ArgoCD GitOps workflow for multi-cluster and multi-tenant configurations.
14. Kustomize with Helm: helmCharts Field
One of the most powerful features added to Kustomize v4.1+ is the helmCharts field. It lets you pull a Helm chart, render it with your values, and then apply Kustomize patches on top — giving you the full power of Kustomize's overlay system over third-party Helm charts without maintaining a fork.
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
helmCharts:
- name: ingress-nginx
repo: https://kubernetes.github.io/ingress-nginx
version: 4.10.0
releaseName: ingress-nginx
namespace: ingress-nginx
valuesFile: ingress-nginx-values.yaml
- name: cert-manager
repo: https://charts.jetstack.io
version: v1.14.5
releaseName: cert-manager
namespace: cert-manager
valuesInline:
installCRDs: true
prometheus:
enabled: true
patches:
- target:
kind: Deployment
name: ingress-nginx-controller
patch: |-
- op: add
path: /spec/template/spec/nodeSelector
value:
role: ingress
helmCharts field requires Helm to be installed on the machine running kustomize build. In ArgoCD, enable the Helm plugin by setting spec.source.kustomize.helmCharts and ensuring the ArgoCD repo-server has Helm available.
This hybrid approach is ideal when you want to consume community Helm charts but manage them through a GitOps workflow with Kustomize overlays. See our Kubernetes Helm Guide for Helm chart authoring and Kubernetes Ingress Guide for ingress-nginx configuration details.
- Write plain YAML in
base/with akustomization.yamllisting resources. - Create overlay directories (
overlays/dev,overlays/prod) each with their ownkustomization.yamlthat references../../base. - Add patches (strategic merge or JSON 6902), image overrides, ConfigMap generators, and components to each overlay.
- Apply with
kubectl apply -k overlays/prodor point ArgoCD at the overlay path. - Use
kustomize edit set imagein CI to update image tags and commit — triggering GitOps sync.
For a comprehensive overview of the full Kubernetes ecosystem, see our Complete Kubernetes Guide.
Kubernetes Articles
Quick Reference
Apply overlay:kubectl apply -k overlays/prod
Preview output:kubectl kustomize overlays/prod
Diff live cluster:kubectl diff -k overlays/prod
Update image tag:kustomize edit set image app=reg/app:v1.2