When do plain Kubernetes manifests applied with kubectl beat writing a Helm chart?
answer
- What does the extra layer buy you
- Count what actually varies
- The file in Git versus the object applied
- Distribution changes the answer
- Adopting Helm later is possible
basics
~20 sWhen there is one deployment target and nothing genuinely varies between deployments. A chart then adds Chart.yaml, templates/ and a values indirection to produce the YAML you already wrote, and reviewers must render it to see what ships.
solid answer
~40 sA Helm chart pays for itself when something varies or someone else installs it. If a telemetry ingest gateway runs in exactly one namespace of one cluster, `values.yaml` becomes a second copy of the manifests with every field spelled twice, and a reviewer reading `{{ if .Values.gateway.tls.enabled }}` has to run `helm template` to know what actually gets applied. The honest test is to list the fields that really differ between deployments: if that list is empty, keep the manifests literal and apply the directory. The chart wins the moment there is a second environment with real differences, a second consumer, a versioned `.tgz` to distribute, subchart composition, or you want the release lifecycle — history, `helm rollback`, `helm uninstall` — rather than just rendering.
code
yaml · 19 linesapiVersion: apps/v1
kind: Deployment
metadata:
name: telemetry-ingest-gateway
spec:
replicas: 3
selector:
matchLabels:
app: telemetry-ingest-gateway
template:
metadata:
labels:
app: telemetry-ingest-gateway
spec:
containers:
- name: gateway
image: registry.internal/telemetry-gateway:2.14.3
ports:
- containerPort: 8080go deeper
Be ready to say plainly what a chart adds — parameterised templates plus a tracked release — and to notice that a single unchanging deployment needs neither. Naming the duplication between values.yaml and templates is enough at this level.
Explain the mechanics that make the tradeoff real: the render step between the file in Git and the applied object, and the specific Helm features (history, rollback, uninstall, hooks) you forgo by applying manifests directly.
Show a decision method rather than a preference. Count the fields that genuinely vary, name who consumes the output, and describe how you would migrate to a chart later using Helm's ownership label and annotations if the answer changes.
Own the standard for the whole estate: when a team may ship literal YAML, when a chart is mandatory because the artefact leaves the team, and what the organisation pays for allowing both shapes to coexist in one repository.
### What a chart actually bundles together A Helm chart is a directory holding `Chart.yaml`, `values.yaml` and a `templates/` folder of Go templates, optionally `_helpers.tpl`, `values.schema.json`, `crds/` and `NOTES.txt`. `helm install` renders those templates with the merged values, applies the result, and stores the rendered manifest plus the values it used in a release record Secret named `sh.helm.release.v1.<name>.v<rev>` in the release namespace. Two separable things arrive in one package: **parameterised rendering** and **a tracked release**. Arguing against a chart means arguing that you need neither — and that argument is sometimes correct. ### The one-environment case Templating exists to collapse N similar manifests into one source plus N parameter sets. When N is one, the collapse saves nothing. A telemetry ingest gateway that runs in a single namespace of a single cluster has one image, one replica count, one resource block, one Service. Written as a chart, every one of those fields appears twice — once as `{{ .Values.gateway.image.tag }}` in the template and once as the literal in `values.yaml` — and the reader must hold both halves in their head to know the result. Be honest about counting environments, though. Dev, staging and production are three, not one, and the moment they differ in replica count, resource limits or hostnames, the parameterisation is doing real work. "One environment" is a narrower claim than most teams' first instinct. ### What the indirection costs The cost of templating is that the artefact under review is no longer the artefact that ships. A pull request against a chart shows a diff of Go template text; whether it produces valid YAML, correct indentation, or the field you intended is only knowable by rendering. Teams that keep charts anyway usually add `helm template` output to code review for exactly this reason. Plain manifests have no such gap: the file in Git is the object that reaches the API server, `kubectl diff` compares it directly, and an editor's schema support and YAML tooling work on it without a render step. There is a second, quieter cost: Helm renders with Go `text/template`, which knows nothing about YAML structure. A conditional in the wrong place emits a document that is syntactically broken or, worse, silently reshaped. Literal manifests cannot fail that way. ### What tips the decision toward a chart - **Real variation.** Fields that genuinely differ across targets, especially if the count of targets is growing. - **Distribution.** If people outside your team install the software, the chart is the interchange format: a versioned `.tgz` with a `values.yaml` contract, optionally a `values.schema.json`, published to a repository with an `index.yaml` or referenced by `oci://`. Nobody outside is going to fork your manifests directory. - **Composition.** Declaring dependencies in `Chart.yaml` so a subchart and its values come along with the parent. - **The release lifecycle.** History, `helm rollback` to a stored revision, `helm uninstall` removing the tracked set, hook ordering, `helm test`. If you want these, you want a release, and a release needs a chart. ### Starting plain is not a one-way door Adopting Helm later is a normal migration rather than a rewrite. Helm recognises objects it owns by the `app.kubernetes.io/managed-by: Helm` label together with the `meta.helm.sh/release-name` and `meta.helm.sh/release-namespace` annotations; existing objects carrying the right values can be adopted by an install, and `--take-ownership` (added in Helm 3.17) exists for the case where they do not carry them yet. Knowing the exit exists is part of why starting with literal YAML is a defensible choice rather than a bet. ### How to answer this in an interview The question is testing whether you can argue against your own tool. A weak answer treats Helm as the default and hunts for excuses; a strong one names the specific benefit each piece of Helm provides, checks whether this system needs that benefit, and picks accordingly. Saying "a chart, because that is how we deploy things" is the answer the question is designed to catch.
- Your team already ships plain manifests and now needs a second environment with two different values. Does that alone justify a chart?Not on its own. Two differing fields across two environments is a small amount of variation, and there are cheaper ways to express it than adopting a full chart, including a second manifest set. The stronger triggers are a growing number of targets, an external consumer who needs a versioned installable artefact, or a genuine need for release history and rollback. Adopt the chart when you want what a release gives you, not merely because a field changed.
- If you keep plain manifests, what do you have to build yourself that Helm would have given you?Ordering between dependent objects, cleanup of resources you removed from the directory, and a record of what was actually applied. Helm tracks the set of objects belonging to a release, so it can prune what left the chart and remove everything on uninstall; a directory of manifests does not track its own membership, so deletions become a manual step someone must remember.
- A colleague argues that a chart is worth it purely so the team can run helm rollback. Is that reasoning sound?It is a real benefit, but check what rollback means to them. `helm rollback` re-applies a stored earlier revision and creates a new revision; it does not restore data or reverse a completed migration. If the recovery path they actually need is re-applying the previous manifests, reverting the commit and applying does the same job. The chart earns its keep here only if they want the stored history and one-command recovery.
Templating is a mould. A mould is a bargain worth making when you will cast the same part many times; casting exactly one part means you built a mould and used it once.
saying these in an interview costs you the question
- Treating a chart as the default packaging for every workload
- Claiming plain manifests cannot be applied declaratively or repeatedly
- Counting dev, staging and production as one environment
- Assuming a chart can never be adopted after starting with plain YAML
- Arguing templating adds no review cost because the rendered output exists