skip to content

Templates & Helpers

templates/ holds one manifest per file, while files like _helpers.tpl render nothing and hold the fullname and labels partials. Asked because a chart you did not write is read file by file.

part ofHelmoverview, primer and where to startread it →
on this pageshow

questions

4

Which files under a Helm chart's templates/ directory do not become Kubernetes manifests?

level: juniorimportance: must knowfreq 62%

answer

  1. Not every file becomes an object
  2. The first character of the name decides
  3. Underscore means partial, not manifest
  4. The extension is irrelevant
  5. Empty renders are dropped, not posted

basics

~20 s

Helm 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 s

Everything 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
yaml
# templates/_ports.tpl - the leading underscore keeps this out of the manifests
{{- define "platform-transcoder-euw-workers.metricsPort" -}}
9187
{{- end -}}

go deeper

for a junior

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.

for a middle

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.

for a senior

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.

for a principal

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

context

open as a page

In a helm create chart, why does the fullname helper truncate to 63 characters?

level: middleimportance: should knowfreq 48%

basics

~20 s

The generated name is used as a Kubernetes label value and often as a Service name, and both are capped at 63 characters. The paired trimSuffix "-" removes a hyphen the cut can leave, which would be illegal.

open as a page

A chart's selectorLabels helper was changed to include the chart version - what breaks on upgrade?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Every chart-version bump now changes the workload's label selector, and a selector is immutable after creation. The next upgrade is rejected by the API server, the release fails, and no flag gets past it: the object must be deleted and recreated.

open as a page

What does helm create scaffold under templates/, and which file is new in Helm 4?

level: middleimportance: nice to knowfreq 24%

basics

~10 s

It writes deployment.yaml, service.yaml, serviceaccount.yaml, ingress.yaml, hpa.yaml, NOTES.txt, _helpers.tpl and tests/test-connection.yaml. Helm 4 adds httproute.yaml beside ingress.yaml, giving the scaffold a second routing option that is off until its values toggle is set.

open as a page