# Kubernetes Overlays with Kustomize: One Base, Many Environments

> Use Kustomize with kubectl to keep one set of manifests and patch them per environment: namespaces, replicas, images, ConfigMaps and strategic merge patches.

- Source: https://www.itwonderlab.com/kustomize-kubernetes-overlays/
- Published: 2026-08-27
- Updated: 2026-08-27
- Author: Javier Ruiz Jiménez (https://www.javierruizjimenez.com/)
- Site: IT Wonder Lab (https://www.itwonderlab.com/)

---

## What is Kustomize

[Kustomize](https://www.itwonderlab.com/kustomize/) customizes [Kubernetes](https://www.itwonderlab.com/kubernetes/) YAML without templates. You keep a **base** with plain manifests and add **overlays** that change only what differs in each environment. It is built into [kubectl](https://www.itwonderlab.com/kubectl-cheat-sheet/), so there is nothing to install.

Use a cluster such as [kind](https://www.itwonderlab.com/kind-local-kubernetes-cluster/) to follow along.

## Layout

```text
app/
  base/
    deployment.yaml
    service.yaml
    kustomization.yaml
  overlays/
    dev/
      kustomization.yaml
    prod/
      kustomization.yaml
      replicas.yaml
```

## The base

```yaml title="base/deployment.yaml"
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: nginx:stable
          ports:
            - containerPort: 80
```

```yaml title="base/service.yaml"
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
  ports:
    - port: 80
```

```yaml title="base/kustomization.yaml"
resources:
  - deployment.yaml
  - service.yaml
```

Render it to see what Kustomize produces, without applying anything:

```bash
kubectl kustomize base
```

## Overlays

The dev overlay puts everything in its own namespace with a name prefix and a pinned image:

```yaml title="overlays/dev/kustomization.yaml"
resources:
  - ../../base
namespace: dev
namePrefix: dev-
images:
  - name: nginx
    newTag: "1.27"
```

The prod overlay changes the number of replicas with a patch file:

```yaml title="overlays/prod/kustomization.yaml"
resources:
  - ../../base
namespace: prod
namePrefix: prod-
patches:
  - path: replicas.yaml
```

```yaml title="overlays/prod/replicas.yaml"
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 4
```

The patch is a partial manifest that is merged with the base by kind and name (a *strategic merge patch*). For small changes use an inline JSON patch:

```yaml
patches:
  - target:
      kind: Deployment
      name: web
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0/image
        value: nginx:1.27-alpine
```

## Apply

```bash
kubectl create namespace dev
kubectl apply -k overlays/dev
kubectl get deploy,svc -n dev

kubectl create namespace prod
kubectl apply -k overlays/prod
kubectl get pods -n prod
```

`kubectl diff -k overlays/prod` shows what would change before you apply. Delete with `kubectl delete -k overlays/prod`.

## Generate ConfigMaps and Secrets

```yaml title="overlays/dev/kustomization.yaml"
configMapGenerator:
  - name: web-config
    literals:
      - LOG_LEVEL=debug
```

The generator appends a hash to the name and updates every reference, so changing the content triggers a rollout of the pods that use it. Do not commit real secrets to Git, even with `secretGenerator`.

## Labels

```yaml
labels:
  - pairs:
      app.kubernetes.io/part-of: shop
    includeSelectors: false
```

Setting selectors after the first deployment is not allowed in Kubernetes, which is why `includeSelectors` is `false` here.

## Kustomize or Helm

Kustomize is simple and has no new language, but it cannot loop or compute values. [Helm](https://www.itwonderlab.com/install-kubernetes-helm/) fits packages that other people install with options. Many teams use Helm for third-party software and Kustomize for their own applications. [Argo CD](https://www.itwonderlab.com/argocd-gitops-kubernetes/) deploys both directly from Git.
