Kustomize lets you customize Kubernetes YAML without templates. Instead of injecting variables into Go templates (like Helm), you write plain, valid YAML and declare how to patch and overlay it for different environments. It's built into kubectl since v1.14.

Without Kustomize
dev/deployment.yaml
staging/deployment.yaml
prod/deployment.yaml
90% identical, 100% duplicated
With Kustomize
base/deployment.yaml
overlays/dev/ +2 lines
overlays/staging/ +4 lines
overlays/prod/ +8 lines
One base, thin overlays per env

Three Core Concepts

Base
Shared, common YAML resources that all environments start from
Overlay
Environment-specific modifications layered on top of a base
kustomization.yaml
The manifest file that declares resources, patches, and transformations

Canonical Directory Structure

my-app/
base/ shared
Common resources for all envs
kustomization.yaml
Lists resources to include
deployment.yaml
Plain K8s manifest
service.yaml
overlays/
Per-environment customizations
dev/
kustomization.yaml
Points to base + dev patches
replicas-patch.yaml
Set replicas: 1 for dev
staging/
kustomization.yaml
prod/
kustomization.yaml
resources-patch.yaml
Increase CPU/memory for prod

How Overlays Stack

base/
deployment.yaml service.yaml configmap.yaml
replicas: 2 · image: myapp:latest · port: 8080
dev
replicas: 1
LOG_LEVEL: debug
resources: minimal
staging
replicas: 2
LOG_LEVEL: info
ingress: enabled
prod
replicas: 5
HPA: enabled
resources: high
base/kustomization.yaml
resources:
  - deployment.yaml
  - service.yaml
  - configmap.yaml
overlays/dev/kustomization.yaml
resources:
  - ../../base

namespace: dev

patches:
  - path: replicas-patch.yaml
How it runs: kubectl apply -k overlays/dev/ reads the overlay's kustomization.yaml, resolves the base, applies patches, and sends the merged YAML to the cluster. No intermediate files generated.

Two Ways to Patch

Kustomize supports two patching strategies. Both modify the base without touching the original files.

Strategic Merge Patch Most common · Intuitive partial YAML

Write a partial resource that gets deep-merged into the base. Only specify the fields you want to change.

Base
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 2
  template:
    spec:
      containers:
        - name: api
          image: myapp:latest
Patch
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 5
  template:
    spec:
      containers:
        - name: api
          resources:
            limits:
              memory: 512Mi
Result
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 5          # changed
  template:
    spec:
      containers:
        - name: api
          image: myapp:latest # kept
          resources:        # added
            limits:
              memory: 512Mi
JSON Patch (RFC 6902) Surgical · For complex operations

An array of operations (add, remove, replace) applied to specific JSON paths. Use when strategic merge can't express your change.

Patch file
- op: replace
  path: /spec/replicas
  value: 5

- op: add
  path: /metadata/labels/env
  value: prod

- op: remove
  path: /spec/template/spec/containers/0/env/2
In kustomization.yaml
patches:
  - path: json-patch.yaml
    target:
      kind: Deployment
      name: api
Use Strategic Merge when…
  • • Changing field values (replicas, image, etc.)
  • • Adding new fields to existing objects
  • • The patch is easy to read as YAML
Use JSON Patch when…
  • • Removing items from arrays
  • • Inserting into specific array positions
  • • Targeting resources by label/annotation

Generators & Transformers

Beyond patches, kustomization.yaml has built-in generators that create resources and transformers that modify all resources at once.

Generators

configMapGenerator
Creates ConfigMaps with content-based hash suffixes for automatic rollout on change.
configMapGenerator:
  - name: app-config
    literals:
      - LOG_LEVEL=info
      - DB_HOST=postgres.svc
    files:
      - config.json
secretGenerator
Creates Secrets (base64-encoded) with the same hash suffix pattern.
secretGenerator:
  - name: db-credentials
    literals:
      - username=admin
      - password=s3cret
    type: Opaque
Why hash suffixes? When config content changes, the generated name changes (e.g., app-config-h8f2k). This forces Deployments referencing the ConfigMap to roll out a new version automatically — no manual restart needed.

Transformers

namespace
Sets namespace on all resources
namespace: production
namePrefix / nameSuffix
Adds prefix/suffix to all resource names
namePrefix: prod-
nameSuffix: -v2
commonLabels
Injects labels into all resources & selectors — prefer labels field
commonLabels:
  app: my-app
  env: prod
commonAnnotations
Adds annotations to all resources
commonAnnotations:
  team: platform
  managed-by: kustomize
images
Override container image names and tags
images:
  - name: myapp
    newTag: v2.1.0
replacements
Copy values between resources (replaces deprecated vars)
replacements:
  - source: ...
    targets: [...]
Kustomize Build Pipeline
1
Load resources
Read all resources listed in kustomization.yaml (local files or remote bases)
2
Run generators
Create ConfigMaps and Secrets from configMapGenerator / secretGenerator
3
Apply patches
Merge strategic patches and execute JSON patches in order
4
Run transformers
Apply namespace, namePrefix, commonLabels, images, and other cross-cutting transforms
5
Emit YAML
Output the final, fully resolved Kubernetes manifests
Build & Apply
kubectl apply -k overlays/dev/ Build & apply in one step
kustomize build overlays/dev/ Preview rendered YAML (stdout)
kustomize build . | kubectl apply -f - Pipe build output to kubectl
Inspect & Debug
kustomize build . | kubectl diff -f - Preview changes before applying
kubectl kustomize overlays/dev/ Same as kustomize build (built-in)
kustomize edit set image myapp:v2 Update image tag in kustomization.yaml
Scaffold
kustomize create Create a new kustomization.yaml
kustomize edit add resource deploy.yaml Add a resource to kustomization.yaml
kustomize edit set namespace prod Set namespace transformer
Advanced
kustomize edit fix Migrate deprecated fields to latest API
kustomize build --enable-helm Enable Helm chart inflation
kustomize build --load-restrictor none Allow loading files outside root

Related Topics