Kustomize adapts plain YAML to each environment without a template language. There are no `{{ }}` placeholders and nothing to install: it ships inside `kubectl` as `apply -k`, and your manifests stay manifests. Use it when Helm's templating is more than you need and dev, staging, and prod really only differ in 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 ``` Those last two patches carry the genuinely cluster-specific fields: `lb-location.yaml` sets `load-balancer.hetzner.cloud/location: fsn1` on the Service, and `storage-class.yaml` points the PersistentVolumeClaims at `local-nvme`. Keep them in the overlay rather than the base, so staging can bind somewhere else. Apply with `kubectl apply -k overlays/prod`, but render it first. `kubectl kustomize overlays/prod | less` shows the exact YAML before it reaches the cluster, and that habit 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.