Understanding _helpers.tpl in Helm Charts
If you’ve ever scaffolded a Helm chart with helm create, you’ve probably noticed a mysterious file called _helpers.tpl sitting inside the /templates folder — and then completely ignored it.
Don’t worry, most people do. But once you understand what it does, you’ll wonder how you ever managed without it.
In this guide, we’re going to demystify _helpers.tpl from the ground up, with a hands-on example you can follow along with.
What You’ll Learn
By the end of this tutorial, you’ll know how to:
- Understand what
_helpers.tplis and why it exists - Define reusable template blocks (called named templates or partials)
- Pull in dynamic values from
chart.yamlandvalues.yaml - Include those blocks across multiple resource templates
- Validate and install a working Helm chart end to end
The Problem It Solves
Before we dive into _helpers.tpl, let’s understand why it exists.
When you write Helm templates for Kubernetes resources — Deployments, Services, ConfigMaps, and so on — you’ll usually want consistent labels on all of them. Something like:
1 | app: my-app |
The natural instinct is to copy and paste this block into every template file. And that works… until you need to change something. Now you’re hunting through five files making the same edit, hoping you didn’t miss one.
There’s a better way. Define those labels once in _helpers.tpl, and reference them from all your other templates. Change it in one place — it updates everywhere.
Think of it like a function in programming. Instead of duplicating logic, you write it once and call it wherever you need it.
What Exactly Is _helpers.tpl?
_helpers.tpl is a special file that lives in your chart’s /templates directory. It contains reusable snippets of template code called named templates (sometimes called partials).
Key insight: Helm treats any file whose name starts with
_as a helper file. It won’t try to render it directly as a Kubernetes manifest. It’s purely there to be called by your other templates.
Here’s the basic anatomy of a named template:
1 | {{- define "my-chart.labels" -}} |
definegives the template a name ("my-chart.labels")- Everything between
defineandendis the reusable content - The
{{-` and `-}}trim whitespace (we’ll come back to why that matters)
To use this block in another template, you call it with include:
1 | metadata: |
The . passes through the current context (so values from chart.yaml and values.yaml are accessible), and nindent 4 makes sure the output is indented by 4 spaces — keeping your YAML valid.
The diagram below shows how this all connects:
1 | _helpers.tpl deployment.yaml / service.yaml |
Hands-On Example: _helpers.tpl in Action
Let’s build a minimal Helm chart that demonstrates exactly how this works.
What We’re Building
- A
_helpers.tplfile that defines a shared label block - Labels that pull values dynamically from
chart.yamlandvalues.yaml - A
deployment.yamlandservice.yamlthat both use those labels - Full validation using
helm template
Step 1: Create the Helm Boilerplate
Start by scaffolding a new Helm chart:
1 | helm create web-app |
This creates a bunch of default files. We’re going to replace them with our own, so clear out the templates directory and the default values file:
1 | rm -rf web-app/templates/* |
Step 2: Create values.yaml
This file holds the configurable values for our chart. Run:
1 | cat > web-app/values.yaml << 'EOF' |
Notice the env field at the bottom — we’re going to use that as a label on our Kubernetes resources.
Step 3: Write the _helpers.tpl File
Now let’s create the star of the show:
1 | cat > web-app/templates/_helpers.tpl << 'EOF' |
Let’s break down what each label does:
| Label | Source | Example Value |
|---|---|---|
app |
Helm release name (set during installation) | web-app |
version |
appVersion field in Chart.yaml |
1.16.0 |
managed-by |
Static value set by Helm | Helm |
env |
env field in values.yaml |
stage |
Note: The
{{-` at the start and `-}}at the end strip leading/trailing whitespace. This is important when you include this block inside YAML, as unexpected blank lines can break things.
Step 4: Create the Deployment Template
Now let’s create a deployment.yaml that uses our helper:
1 | cat > web-app/templates/deployment.yaml << 'EOF' |
You’ll notice include "web-app.labels" appears twice — once for the Deployment’s own metadata labels, and once for the Pod template’s labels. Both use the same helper, and both stay in sync automatically.
The nindent 4 and nindent 8 simply control how many spaces to indent the output so the YAML remains valid.
Step 5: Create the Service Template
Same idea for the service:
1 | cat > web-app/templates/service.yaml << 'EOF' |
Step 6: Validate the Rendered Output
Before installing anything, use helm template to preview what Helm will actually generate:
1 | helm template web-app ./web-app |
You should see both the Deployment and Service rendered, each with the labels block filled in:
1 | labels: |
Both resources get the exact same labels — defined in one place, rendered everywhere. If you ever need to change managed-by to helm-managed, you change it in _helpers.tpl and it updates everywhere automatically.
Step 7: Install the Chart
If everything looks right, go ahead and install:
1 | helm install web-app ./web-app |
Expected output:
1 | NAME: web-app |
Now verify the labels were applied correctly:
1 | kubectl get deploy web-app --show-labels |
You should see:
1 | NAME READY UP-TO-DATE AVAILABLE AGE LABELS |
Step 8: Clean Up
When you’re done experimenting:
1 | helm uninstall web-app |
What Else Can You Put in _helpers.tpl?
Labels are the most common use case, but you can define any reusable template logic:
- Image name construction — combine repository and tag into a single string
- Resource name prefixes — ensure consistent naming across resources
- Selector labels — separate from regular labels so selectors stay stable across upgrades
- Annotations — reusable annotation blocks, just like labels
Here’s a quick example of a more advanced helper that builds an image string:
1 | {{- define "web-app.image" -}} |
Then in your Deployment:
1 | image: {{ include "web-app.image" . }} |
Things to Keep in Mind
- Keep helpers focused.
_helpers.tplis for reusable template logic, not application configuration. Don’t use it as a dumping ground for complex business rules. - Don’t over-engineer. Helm’s templating is powerful, but deeply nested or recursive partials are hard to debug. Keep things readable.
- Any file starting with
_works. You can split helpers across multiple files like_labels.tpl,_images.tpl, etc. if your chart grows large. Helm will pick them all up.
Conclusion
_helpers.tpl is one of those features that seems optional right up until you find yourself editing the same label block in five different files. Once you start using it, you’ll never go back.
To recap what we covered:
_helpers.tplholds reusable named templates that can be referenced from any other template in your chart- Use
defineto create a named template, andincludeto use it - Dynamic values from
chart.yamlandvalues.yamlare fully accessible inside helpers nindentkeeps your YAML indentation valid when including blocks- Files starting with
_are never rendered as Kubernetes manifests — they exist only to be called
Give it a try on your next Helm chart — your future self will thank you.





