Writing Kustomize Overlays
Kustomize builds a final manifest set from a base (shared definitions) and one or more overlays (environment-specific additions and patches). You never modify the base to deploy to a specific environment. Instead, an overlay references the base and layers changes on top.
Directory layout
Section titled “Directory layout”This project keeps infrastructure and applications separate, but both follow the same pattern:
infrastructure/ base/ kustomization.yaml # references monitoring/, traefik/ overlays/ local/ kustomization.yaml traefik-patch.yaml ingressroute-dashboard.yaml ingressroute-grafana.yaml
apps/ base/ docs/ kustomization.yaml # namespace, deployment, service overlays/ dev/ docs/ kustomization.yaml ingressroute.yamlBase kustomizations
Section titled “Base kustomizations”A base kustomization.yaml lists the resources it owns. The infrastructure base references subdirectory names — Kustomize treats a directory name as a path to another kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources: - monitoring - traefikThe docs app base lists files directly:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources: - namespace.yaml - deployment.yaml - service.yamlNeither base knows anything about the environment. They define the minimum set of resources every environment needs.
Adding resources in an overlay
Section titled “Adding resources in an overlay”An overlay references its base with a relative path under resources, then lists any additional files alongside it:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources: - ../../base - ingressroute-dashboard.yaml - ingressroute-grafana.yamlpatches: - path: traefik-patch.yaml../../base resolves to infrastructure/base/, which Kustomize expands recursively. The two IngressRoute files are local to the overlay — they expose the Traefik dashboard and Grafana at *.k8s.local hostnames that only exist in the local cluster.
The docs overlay follows the same structure:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources: - ../../../base/docs - ingressroute.yamlingressroute.yaml adds a Traefik IngressRoute that routes docs.k8s.local to the docs service over TLS. The base has no IngressRoute at all — routing is an overlay concern because the hostname and TLS configuration differ per environment.
Patching existing resources
Section titled “Patching existing resources”The patches field modifies resources that already exist in the base output. traefik-patch.yaml is a strategic-merge patch: it targets the HelmRelease named traefik and merges only the fields it specifies.
apiVersion: helm.toolkit.fluxcd.io/v2kind: HelmReleasemetadata: name: traefik namespace: flux-systemspec: values: api: dashboard: true insecure: true service: type: ClusterIP tlsStore: default: defaultCertificate: secretName: mkcert-wildcardKustomize matches this patch to the existing HelmRelease by apiVersion, kind, and metadata.name. In the local environment, Traefik runs as ClusterIP (no external IP) and uses a locally-issued wildcard certificate. A production overlay would patch different values — or omit the patch entirely.
Building and applying
Section titled “Building and applying”Run kubectl kustomize to preview the merged output, then pipe it to apply:
# Preview what Kustomize will producekubectl kustomize infrastructure/overlays/local
# Apply directlykubectl apply -k infrastructure/overlays/localFlux can also apply a kustomization automatically by pointing a Kustomization resource at an overlay path in the repository.
Key rules
Section titled “Key rules”- Never modify the base for a specific environment. All environment differences belong in an overlay.
- Overlays reference bases by relative path. Use
../../baseor../../../base/docs— the path must resolve to a directory containing akustomization.yaml. - Patches target by identity. A strategic-merge patch must include
apiVersion,kind,metadata.name, andmetadata.namespaceto match the right resource. - Additional resources are overlay-local. Files like
ingressroute.yamllive next to the overlay’skustomization.yamland are not visible to the base or other overlays.