Kustomize Footguns¶
Mistakes that cause outages or security incidents.
1. Patch Target Name Mismatch — Patch Silently Skipped¶
You write a strategic merge patch to increase replicas, but use a slightly different resource name than what's in the base (e.g., myapp-deployment vs myapp). Kustomize silently skips patches that don't match any resource — there is no error, no warning. You apply to production, confident your replicas were set to 5, and find the base's single replica is still running.
Fix: Always build and inspect before applying: kubectl kustomize overlays/production/ | grep -E "replicas|name:". Verify the patch's metadata.name matches the base resource name exactly, including case. Add a CI step that builds and diffs every overlay on pull requests.
Gotcha: Kustomize's silent skip behavior is the most dangerous design choice in the tool. Unlike Helm (which errors on unknown values), Kustomize simply ignores patches that do not match. A typo in a resource name means your patch does nothing — with zero feedback. Always diff the rendered output in CI.
2. Images Transformer Name Must Match Exactly (Including Registry)¶
The images transformer in kustomization.yaml silently does nothing if the name field doesn't match the image string in the base deployment exactly. If your base has image: docker.io/myorg/myapp:v1.0.0, you must use name: docker.io/myorg/myapp — not myapp or myorg/myapp. Engineers waste time wondering why the image tag never changes in the deployed pods.
Fix: Run kustomize build base/ | grep image: to see the exact image string, then copy that as the name in the images transformer. After adding the transformer, run kustomize build overlays/production/ | grep image: to confirm the tag changed. In CI, fail the pipeline if any image in the rendered output still has the old tag.
3. disableNameSuffixHash: true Defeats ConfigMap Rotation¶
You disable the name suffix hash on a configMapGenerator entry because you want a predictable ConfigMap name. Now when you update the ConfigMap content, the name stays the same. Kubernetes Deployments that reference the ConfigMap are not automatically restarted — they keep reading the old config from the pod's cached volume. The change appears applied (kubectl shows the new ConfigMap content) but pods are still using stale config.
Fix: Only use disableNameSuffixHash: true for ConfigMaps that do not need to trigger pod restarts (e.g., referenced by label selectors, not by exact name). For application config that should trigger restarts, keep the hash suffix enabled and let Kustomize manage the rolling update automatically — this is the entire point of the feature. If you need predictable names, add an annotation: configmap-version: v2 to force a rollout.
4. Committing Secrets to Git via secretGenerator¶
The secretGenerator lets you reference a local secrets.env file. Engineers forget to add this file to .gitignore and commit it to the repository. The secrets are now in git history — base64-encoded in the rendered kustomization output, but plaintext in the source file. Even after deleting the file, git log preserves it forever.
Fix: Add any file referenced by secretGenerator to .gitignore before creating it. Add a pre-commit hook that detects secrets.env or similar files. Better yet: don't use secretGenerator for production secrets at all — use External Secrets Operator (ESO) to sync secrets from Vault or AWS Secrets Manager into Kubernetes, keeping plaintext secrets entirely out of the repository.
Remember: Even after
git rm secrets.env, the file persists in git history. Purging it requiresgit filter-branchorgit filter-repoacross all branches and force-pushing — which is disruptive and may not catch every clone. Prevention (pre-commit hooks + .gitignore) is far cheaper than remediation.
5. Wrong bases vs resources Syntax (v1beta1 vs v1)¶
Kustomize v2 introduced resources to replace bases for referencing other kustomization directories. In kustomize.config.k8s.io/v1beta1, bases works. In kustomize.config.k8s.io/v1, bases is removed — only resources is valid. Engineers copy-paste old examples with bases:, update the apiVersion to v1, and get cryptic "field not allowed" errors that are hard to trace.
Fix: Use resources: for everything in modern Kustomize (the resources: field handles both raw YAML files and references to other kustomization directories). If you see bases: in an existing kustomization.yaml, replace it with resources:. Always use apiVersion: kustomize.config.k8s.io/v1beta1 or check the Kustomize version's supported API to avoid mixed usage.
6. kubectl's Bundled Kustomize Is Older Than Standalone¶
kubectl apply -k uses a version of Kustomize bundled into kubectl, which lags behind the standalone kustomize CLI by several versions. Features you tested with kustomize build — Helm inflation, newer patch syntax, replacements: — may silently fail or error when applied via kubectl apply -k in CI or by a teammate on an older kubectl version.
Fix: Pin the standalone kustomize binary version in your CI pipeline and use it explicitly (kustomize build overlays/prod | kubectl apply -f -) rather than relying on kubectl apply -k. Check kubectl's bundled kustomize version with kubectl version --client. Document the required kustomize version in your repo's README or a .tool-versions file (asdf).
Debug clue: If
kustomize buildworks locally butkubectl apply -kfails in CI, check the kubectl version. kubectl 1.27 bundles kustomize v5.0.1; kubectl 1.25 bundles v4.5.7. Features likereplacements:and Helm inflation may not exist in the older bundled version.
7. Namespace Field in Kustomization Overrides All Resource Namespaces¶
You add namespace: production to an overlay's kustomization.yaml expecting it to apply to only the resources that don't already have a namespace. It actually overrides the namespace of every namespaced resource in the build output — including resources that already specified namespace: staging in the base. Resources that were supposed to live in staging now get created in production.
Fix: Understand that Kustomize's namespace: field at the kustomization.yaml level is a transformer that replaces (not sets-if-empty) the namespace on all namespaced resources. If base resources deliberately target different namespaces, do not use the top-level namespace: field — use a targeted patch instead. Review kustomize build overlays/production/ | grep namespace: before every first-time apply to a new overlay.
8. Using Kustomize for Everything When Helm Is the Right Tool¶
Your team uses Kustomize to manage a complex third-party application deployment with 20 resources, 15 configurable parameters, and 3 environments. You build a elaborate overlay structure with dozens of patches to handle every parameter. Six months later, the upstream application releases a new version with changed resource names. Every single patch breaks. You spend days manually updating 40 patch files.
Fix: Use Helm for third-party applications — charts are designed to absorb upstream changes via values files. Kustomize excels at environment-specific overlays on top of your own plain YAML. A common effective pattern: use Helm to render the third-party chart (helm template > base.yaml), commit that as the base, and use Kustomize to patch it for your environment. When upgrading the chart, re-render and commit the new base.