Kustomize Bases: Shared Manifests for Overlays
A base is a Kustomization directory holding the common manifests that one or more overlays extend.
The base/overlay split is the core Kustomize pattern: one base of shared YAML, then per-environment overlays that patch it. The old bases field is now just resources.
What it does
A base is an ordinary Kustomization directory. An overlay references it from its resources list and layers on patches, name prefixes, namespaces, and image overrides. The legacy bases field did the same job and is now folded into resources.
Common usage
# overlays/prod/kustomization.yaml
resources:
- ../../base
patches:
- path: replica-count.yaml
images:
- name: myapp
newTag: 1.4.2Layout
| Path | Role |
|---|---|
| base/kustomization.yaml | Shared resources and defaults |
| overlays/dev/kustomization.yaml | References ../../base, dev tweaks |
| overlays/prod/kustomization.yaml | References ../../base, prod tweaks |
| bases: (deprecated) | Old field; use resources instead |
In CI
Render each overlay separately: kustomize build overlays/prod. Do not apply the base directly in CI; apply the built overlay so environment-specific patches are included. If you still use the bases field, migrate it to resources to silence deprecation warnings on newer kustomize.
Common errors in CI
"bases is deprecated: please use resources instead" is a warning, not a failure, but newer versions may eventually drop it. "accumulating resources ... must contain a kustomization.yaml" means the overlay points at a directory that is not a Kustomization. A patch that targets a resource not present in the base fails with "no matches for Id".
Using this in CI
A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods
# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info
# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes