Introduction
Kustomize modifies Kubernetes YAML without templates by applying patches to base configurations. Replacing items in a list (like containers, volumes, or env vars) is one of the trickiest operations because YAML lists do not have keys — Kustomize uses Strategic Merge Patches that match list items by a merge key (usually name). For lists without merge keys, you need JSON 6902 patches that target items by array index.
Strategic Merge Patch (Match by Name)
Kubernetes strategic merge patches match list items by their merge key. For containers, the merge key is name:
1# base/deployment.yaml
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: my-app
6spec:
7 template:
8 spec:
9 containers:
10 - name: app
11 image: myapp:1.0
12 resources:
13 limits:
14 memory: "128Mi"
15 cpu: "250m"
1# overlays/production/patch.yaml
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: my-app
6spec:
7 template:
8 spec:
9 containers:
10 - name: app # Matches by name
11 image: myapp:2.0 # Replaced
12 resources:
13 limits:
14 memory: "512Mi" # Replaced
15 cpu: "1000m" # Replaced
1# overlays/production/kustomization.yaml
2apiVersion: kustomize.config.k8s.io/v1beta1
3kind: Kustomization
4resources:
5 - ../../base
6patchesStrategicMerge:
7 - patch.yaml
kustomize build overlays/production
# Result: container "app" has image myapp:2.0 and updated resources
JSON 6902 Patch (Match by Index)
For precise control or when items have no merge key, use JSON 6902 patches:
1# overlays/production/kustomization.yaml
2apiVersion: kustomize.config.k8s.io/v1beta1
3kind: Kustomization
4resources:
5 - ../../base
6patches:
7 - target:
8 kind: Deployment
9 name: my-app
10 path: patch.yaml
1# overlays/production/patch.yaml
2# Replace the entire first container
3- op: replace
4 path: /spec/template/spec/containers/0
5 value:
6 name: app
7 image: myapp:2.0
8 resources:
9 limits:
10 memory: "512Mi"
11 cpu: "1000m"
12
13# Replace just the image of the first container
14- op: replace
15 path: /spec/template/spec/containers/0/image
16 value: myapp:2.0
17
18# Replace a specific env var (third item in env list)
19- op: replace
20 path: /spec/template/spec/containers/0/env/2/value
21 value: "new-value"
Adding Items to a List
1# JSON 6902 — add a new container to the list
2- op: add
3 path: /spec/template/spec/containers/-
4 value:
5 name: sidecar
6 image: sidecar:latest
7 ports:
8 - containerPort: 9090
9
10# Add a new env var to the first container
11- op: add
12 path: /spec/template/spec/containers/0/env/-
13 value:
14 name: NEW_VAR
15 value: "hello"
The - at the end of the path means "append to the array."
Removing Items from a List
1# Remove the second container (index 1)
2- op: remove
3 path: /spec/template/spec/containers/1
4
5# Remove a specific env var by index
6- op: remove
7 path: /spec/template/spec/containers/0/env/0
Replacing Environment Variables
Environment variables are a common list replacement scenario:
1# base/deployment.yaml
2spec:
3 template:
4 spec:
5 containers:
6 - name: app
7 image: myapp:1.0
8 env:
9 - name: DATABASE_URL
10 value: "postgres://localhost:5432/dev"
11 - name: LOG_LEVEL
12 value: "debug"
13 - name: API_KEY
14 valueFrom:
15 secretKeyRef:
16 name: app-secrets
17 key: api-key
1# Strategic merge patch — matches env items by name
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: my-app
6spec:
7 template:
8 spec:
9 containers:
10 - name: app
11 env:
12 - name: DATABASE_URL
13 value: "postgres://prod-db:5432/production"
14 - name: LOG_LEVEL
15 value: "warn"
Inline Patches
For small changes, define patches inline in kustomization.yaml:
1apiVersion: kustomize.config.k8s.io/v1beta1
2kind: Kustomization
3resources:
4 - ../../base
5patches:
6 - target:
7 kind: Deployment
8 name: my-app
9 patch: |-
10 - op: replace
11 path: /spec/template/spec/containers/0/image
12 value: myapp:2.0
13 - op: replace
14 path: /spec/replicas
15 value: 3
Using replacements (Kustomize 4.5+)
The replacements field provides a declarative way to copy values between resources:
1apiVersion: kustomize.config.k8s.io/v1beta1
2kind: Kustomization
3resources:
4 - ../../base
5replacements:
6 - source:
7 kind: ConfigMap
8 name: app-config
9 fieldPath: data.image_tag
10 targets:
11 - select:
12 kind: Deployment
13 name: my-app
14 fieldPaths:
15 - spec.template.spec.containers.[name=app].image
Common Pitfalls
Strategic merge patch replacing the entire list: If you include a list in a strategic merge patch but omit existing items, those items are not deleted — they remain because the merge matches by the name key. However, if you use a plain merge patch (not strategic), the entire list is replaced.
Wrong array index in JSON 6902: Array indices are zero-based. Targeting /containers/1 when there is only one container results in path not found. Verify the base manifest's list length before patching by index.
Merge key mismatch: Strategic merge patches match containers by name, volumes by name, ports by containerPort. If the name in your patch does not match any item in the base, a new item is added instead of replacing the existing one.
Patching items with no merge key: Some lists (like args, command) have no merge key. Strategic merge patches replace the entire list in these cases. Use JSON 6902 patches for precise item-level control.
Order of patch application: Kustomize applies patches in the order listed in kustomization.yaml. Later patches see the result of earlier ones. If two patches modify the same list item, the second patch operates on the already-modified version.
Summary
Use strategic merge patches to replace list items by their merge key (usually name)
Use JSON 6902 patches (op: replace, op: add, op: remove) for index-based or precise list modifications
The - path suffix appends to an array; numeric indices target specific positions
Environment variables and containers use name as the merge key for strategic merge patches
Verify base manifest structure with kustomize build before writing patches to ensure correct paths