Which files under a Helm chart's templates/ directory do not become Kubernetes manifests?
answer
- Not every file becomes an object
- The first character of the name decides
- Underscore means partial, not manifest
- The extension is irrelevant
- Empty renders are dropped, not posted
basics
~20 sHelm evaluates every file under templates/, but output from a file whose name begins with an underscore or a dot never becomes a manifest. NOTES.txt becomes the release notes, and a file rendering to only whitespace is dropped.
solid answer
~50 sEverything under `templates/` is parsed and evaluated, including subdirectories, but not everything reaches the cluster. Helm's convention is that a file whose base name starts with `_` holds no manifest, so its output is discarded when the render is split into Kubernetes objects; that is why the scaffolded partial file is called `_helpers.tpl`. Files starting with `.` are ignored the same way, `NOTES.txt` is special-cased into the release notes, and any file whose rendered output is nothing but blank lines and comments is dropped rather than sent as an empty document. The trigger is the leading underscore, not the `.tpl` extension and not the exact name `_helpers.tpl` — you can freely split partials into `_labels.tpl`, `_pod.tpl` and so on. To see what actually survived, run `helm template` and read the `# Source:` comment above each document.
code
yaml · 4 lines# templates/_ports.tpl - the leading underscore keeps this out of the manifests
{{- define "platform-transcoder-euw-workers.metricsPort" -}}
9187
{{- end -}}go deeper
Remember the underscore rule and be able to point at _helpers.tpl and say why it produces nothing. Knowing that helm template prints a # Source: comment per document is enough to answer most follow-ups on the spot.
Explain the mechanics: recursive walk, the split into documents, the discard of underscore- and dot-prefixed output, NOTES.txt as release notes, and whitespace-only output being dropped so a disabled conditional file is harmless.
Show how you use this when reading an unfamiliar chart: grep the # Source: comments to map objects back to files, and recognise that a partial silently overridden by a subchart is a real failure mode the naming convention exists to prevent.
Own the convention across a chart estate: a house rule on file granularity, on where partials live, and on prefixing every named template, so that charts written by different teams can be composed as subcharts without silently overwriting each other's definitions.
## What `templates/` actually is A chart's `templates/` directory is the set of files Helm evaluates to produce the Kubernetes objects a release installs. Helm walks the directory recursively — subdirectories are rendered too, and a file's path relative to the chart root becomes the name Helm knows it by, such as `templates/tests/test-connection.yaml`. After evaluation Helm splits the combined output into individual manifests, sorts them into install order and sends them to the API server. Not every file is meant to produce an object, and Helm needs a way to tell the difference without parsing your intent. The rule is purely a naming convention on the file, applied before the output is treated as manifests: - **A base name beginning with `_`** — the file's output is discarded. This is the partials convention: files like `_helpers.tpl` exist only to declare named templates that other files pull in. - **A base name beginning with `.`** — ignored in the same way, which keeps editor and tooling dotfiles from being interpreted as objects. - **`NOTES.txt`** — evaluated like any other template, but its output becomes the human-readable notes printed after `helm install` rather than a manifest. - **Anything that renders to only whitespace and comments** — dropped. This is what makes a conditional file such as `ingress.yaml` safe: when the guarding value is false, the file contributes nothing and Helm does not attempt to POST an empty document. ## The underscore is the trigger, not the extension The most common misreading is that `.tpl` is the magic part. It is not. `templates/_ports.tpl`, `templates/_ports.yaml` and `templates/_ports` are all skipped for exactly the same reason: the leading underscore. Conversely, a file called `helpers.tpl` with no underscore *will* be treated as a manifest source, and if it only declares named templates it renders to nothing and is silently dropped — which looks fine until someone adds a stray line of output to it. Nor is `_helpers.tpl` a name Helm looks for. It is simply what `helm create` writes. A large chart is perfectly free to split its partials across several underscore-prefixed files by concern, and readers of that chart will find them faster than they would find one 300-line file. ## Why partials need a chart-name prefix Named templates declared in these files do **not** live in the file that declares them, and they are not scoped to the chart either. Every named template in a chart *and every one in its subcharts* shares a single flat namespace for the whole render. Two charts that both declare a template called `labels` collide, and the definition parsed last wins — silently, with no error. That is the reason the scaffold names every partial after the chart, as in `platform-transcoder-euw-workers.labels`. Prefixing is not decoration; it is the only collision protection there is. ## One object per file The one-manifest-per-file layout is a readability convention, not a requirement. A single file may hold several YAML documents separated by `---`, and Helm splits them normally. The cost is traceability: `helm template` emits a `# Source: <chart>/templates/<file>` comment before each document, and when four objects share one file that comment stops telling you where to edit. Keeping `deployment.yaml`, `service.yaml` and `serviceaccount.yaml` separate means a reader who is given an object name can find the file that produced it in one step, which matters most on a chart nobody on the current team wrote. ## Seeing the result Two commands settle any argument about what a chart produces. `helm template <name> <chart>` prints the rendered manifests locally with their `# Source:` comments, so grepping those comments lists exactly which files produced output. `--show-only templates/deployment.yaml` narrows it to one file, and asking for a file that renders to nothing returns an error rather than an empty result — which is itself a fast way to confirm that a conditional file is switched off. For a release that is already installed, `helm get manifest` prints what was actually stored for it.
- Does each file under templates/ have to contain exactly one Kubernetes object?No. A file may hold several YAML documents separated by `---` and Helm splits them into separate manifests. One object per file is a readability convention: `helm template` prints a `# Source:` comment naming the file above each document, so a reader handed an object name can jump straight to the file that produced it. Bundling four objects into one file makes that comment much less useful.
- Are subdirectories under templates/ rendered?Yes, Helm walks the directory recursively. The path relative to the chart root is the template's name, which is why `helm create` can put its chart test in `templates/tests/test-connection.yaml` and why `--show-only` takes a path like `templates/tests/test-connection.yaml`. Grouping a large chart's files into subdirectories is legal and costs nothing at render time.
- Why does helm create prefix every named template with the chart name?Named templates share one flat namespace across the chart and all of its subcharts. An unprefixed `labels` definition in a subchart and one in the parent collide, and the definition parsed last silently wins — so a subchart can quietly change the parent's labels. Prefixing every `define` with the chart name, as the scaffold does, is what keeps that from happening.
Think of templates/ as a print job: every page is typeset, but the pages whose names start with an underscore are the style sheets, and they are pulled out of the stack before it goes in the envelope.
saying these in an interview costs you the question
- Claiming the .tpl extension is what stops a file rendering
- Believing _helpers.tpl is a filename Helm requires
- Thinking partials are private to the file declaring them
- Saying each file must hold exactly one object
- Assuming files in subdirectories of templates/ are ignored
- Expecting NOTES.txt to be applied to the cluster