Kustomize adapts plain YAML to each environment without a template language. There are no `{{ }}` placeholders, and there is nothing to install: it ships inside `kubectl` and runs as `apply -k`, so your manifests stay valid YAML you can read and apply on their own. Use it when Helm's templating is more than you need and your environments (dev, staging, prod) differ in only a handful of fields. ## Base and overlays One base holds the real manifests; one overlay per environment patches what differs. ```text app/ base/ deployment.yaml service.yaml kustomization.yaml overlays/ staging/kustomization.yaml prod/kustomization.yaml ``` The base's `kustomization.yaml` lists its resources. Each overlay points back at the base and layers the environment on top: ```yaml title="overlays/prod/kustomization.yaml" resources: - ../../base namePrefix: prod- images: - name: your/app newTag: "1.4.0" # prod pins a released tag patches: - path: replicas.yaml # prod runs more replicas per pool - path: lb-location.yaml # place the LoadBalancer in Falkenstein - path: storage-class.yaml # bind PVCs to local-nvme ``` The last two patches hold the cluster-specific settings: `lb-location.yaml` sets `load-balancer.hetzner.cloud/location: fsn1` on the Service, and `storage-class.yaml` points the PersistentVolumeClaims at `local-nvme`. Keep these in the overlay rather than the base, so each environment can use different values. Apply the overlay with `kubectl apply -k overlays/prod`, but render it first: `kubectl kustomize overlays/prod | less` shows the exact YAML before it reaches the cluster, which catches most mistakes. ## What an overlay can change - **`images`** swaps a tag per environment: prod pins a release, staging tracks latest. - **`namePrefix` / `nameSuffix`** and **`namespace`** keep each environment's objects distinct. - **`patches`** rewrite any field (replica count, resource requests, an env var, a LoadBalancer annotation) as a strategic-merge or JSON patch. - **`configMapGenerator` / `secretGenerator`** build config from files or literals and hash the name, so editing the content changes the name and the rollout happens on its own. That is the same trick a [checksum annotation](/docs/hetzner/apalla/workloads/delivery/config-maps-and-secrets) does by hand, done for you. ## Helm or Kustomize Both parameterize manifests; they start from opposite ends. Use **Kustomize** to adapt manifests you already own, layering small per-environment differences over a shared base in plain YAML. Use **[Helm](/docs/hetzner/apalla/workloads/delivery/deploy-with-helm)** to install and version packaged software, especially third-party charts. Many teams run both: Helm for off-the-shelf components, Kustomize for their own manifests, and let [Argo CD](/docs/hetzner/apalla/workloads/delivery/deploy-apps-from-git-argo-cd) render either straight from Git so a merged pull request is the deploy.