Kustomize’s patchesStrategicMerge is the secret weapon for applying targeted modifications to Kubernetes manifests without getting bogged down in Helm’s templating logic.

Let’s see Kustomize patchesStrategicMerge in action. Imagine you have a base Kubernetes deployment manifest:

# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: nginx:1.21.3
        ports:
        - containerPort: 80

And you want to increase the replica count to 3 and change the image tag to nginx:1.22.0 for a specific environment, say production, without touching the original deployment.yaml. This is where patchesStrategicMerge shines.

Your Kustomize configuration (kustomization.yaml) would look like this:

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - base/deployment.yaml

patchesStrategicMerge:
  - patches/deployment-patch.yaml

And the patch file:

# patches/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: default
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: my-app-container
        image: nginx:1.22.0

When you run kustomize build ., the output will be:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: nginx:1.22.0
        ports:
        - containerPort: 80

Notice how replicas is now 3 and the image has been updated, while the rest of the original manifest remains intact. Kustomize intelligently merges the patch based on apiVersion, kind, metadata.name, and metadata.namespace.

The problem patchesStrategicMerge solves is managing variations of Kubernetes configurations across different environments or stages without resorting to complex templating engines. Helm excels at packaging and managing releases, but for declarative, component-level configuration patching within a GitOps workflow, Kustomize’s approach is often simpler and more direct. It allows you to maintain a clean "base" set of manifests and apply specific, targeted overrides as needed, keeping your Git history focused on the changes rather than the entire rendered template.

Internally, patchesStrategicMerge works by performing a strategic merge. Kubernetes has a concept of "strategic merge patch" which is more powerful than a simple JSON merge patch. It understands the structure of Kubernetes objects and can intelligently merge lists and other complex fields. Kustomize leverages this by identifying the target object in the patch (using apiVersion, kind, and metadata.name) and then merging the fields from the patch into the base object. For fields like replicas or image, it’s a straightforward replacement. For more complex structures like container lists, it merges based on the name field of the container. This is why you only needed to specify name: my-app-container in the patch, and Kustomize knew to update the image for that specific container.

The exact levers you control are the resources field in your kustomization.yaml, which points to your base manifests, and the patchesStrategicMerge field, which lists the patch files. Each patch file targets a specific resource and contains the exact fields you want to override. You can have multiple patches, and Kustomize will apply them in the order they are listed. This granular control means you can have distinct patches for development, staging, and production, each applying only the necessary modifications.

A common misconception is that patchesStrategicMerge is a full-blown templating system. It’s not. It’s a declarative patching mechanism. You are not writing logic or loops; you are providing a partial object that Kustomize merges with the base. The "strategic" part comes from Kubernetes’s understanding of how to merge different object types, especially lists where elements are identified by specific fields like name. For instance, if you had multiple containers in your base deployment and wanted to update a specific one, you’d include that container’s name in the patch, and Kustomize would find and update it.

If you find yourself wanting to conditionally include entire resources or generate values based on external data, you’ll likely start looking into Kustomize’s generators and transformers, which are distinct but complementary features.

Want structured learning?

Take the full Kustomize course →