In Lesson 1, you learned Go templating basics: variables, pipelines, conditionals, ranges. You can now write templates that branch on conditions and loop through data.
But you discovered a problem: You're repeating the same labels (app: myapp, version: 1.0, env: prod) in your Deployment, Service, and ConfigMap. That's not a templating problem—that's a code repetition problem. You need a way to define template fragments once and reuse them everywhere.
This lesson introduces named templates and the _helpers.tpl convention—the DRY principle for Helm charts. You'll define common patterns once (labels, selectors, image pull secrets, annotations) and include them wherever needed.
This lesson teaches you how to eliminate template duplication using Helm's named templates and helper conventions.
Prerequisites:
Time Estimate: 45 minutes
In Lesson 1, every template you wrote was a full file that produced output. But templates can also define functions that output nothing on their own.
The define action creates a named template:
Key points:
Output:
When you define a template, nothing appears. The template is registered in memory, waiting to be called.
Helm has a naming convention: Templates starting with _ (underscore) are not rendered as standalone manifests. They're utilities meant to be included elsewhere.
Create templates/_helpers.tpl:
Why _helpers.tpl?
Output:
No files are created. _helpers.tpl is never rendered. It only provides functions for other templates to include.
Now you call a named template using include:
Syntax breakdown:
Output:
Helm originally provided template for calling named templates. template is now deprecated (removed in Helm 3.13+).
Why? The problem is output handling.
Problem with template:
template doesn't support pipes. You can't control indentation. Output becomes:
Notice: No indentation. YAML is broken.
Solution with include:
include returns a string that you can pipe to nindent. Output:
Properly indented. Valid YAML.
Output comparison:
template (broken indentation):
include (correct):
Key difference:
Always use include. Never use template for new code.
Quick Reference:
Self-Check Questions:
When you call a named template, you pass . as the current context. Inside the template, . refers to whatever you passed.
When you call:
Inside myapp.labels, . is the root context (.Chart, .Values, etc. all work).
Scope rule: Inside a named template, . refers to whatever you passed to include/template.
Common mistake:
Inside the range, . becomes each tag string. You can't access .Chart anymore.
To access both root context and loop value:
$ is a special variable: Always refers to root context, no matter how deep you nest.
Used in every Kubernetes manifest.
Used in Deployments, Services, StatefulSets.
Only rendered if imagePullSecrets is defined.
Combines defaults with conditional fields.
The standard Helm convention is: chartname.component
Examples from real charts:
Your chart: myapp.labels, myapp.selector, myapp.imagePullSecrets
Why this pattern?
Quick Reference:
Self-Check Questions:
Before you start the exercises, avoid these frequent errors:
Wrong:
Why it fails: The template can't access .Chart, .Values, etc. without context.
Correct:
Wrong:
Why it fails: Labels are already at 4-space indent (under metadata:), but nindent 2 only indents 2 spaces.
Correct:
Rule: Count the spaces from the left margin to where the first key should appear.
Wrong:
Why it fails: Can't pipe to nindent, breaks YAML indentation.
Correct:
Wrong:
Why it fails: If you use a subchart that also defines labels, they collide.
Correct:
Wrong:
Correct:
Create templates/_helpers.tpl:
Verify it's not rendered:
Output:
No YAML with app: aiagent appears. The template is defined but not rendered.
Create templates/deployment.yaml:
Create templates/service.yaml:
Create templates/configmap.yaml:
Render:
Output:
Three manifests (Deployment, Service, ConfigMap) all include the same labels from your helper.
Update templates/_helpers.tpl:
Update values.yaml:
Use in templates/deployment.yaml:
Render:
Output:
Change values.yaml to imagePullSecrets: [] and render again:
Output:
The imagePullSecrets section is omitted.
Create a test file using old template syntax:
Render:
Output (BROKEN):
YAML is invalid. Labels aren't indented under labels:.
Now use include:
Output (CORRECT):
Valid YAML, proper indentation.
You have three manifests with duplicate metadata.labels:
Before:
After:
Create helper in _helpers.tpl:
Use in all three:
Benefit: Change labels once in _helpers.tpl. All three manifests automatically use the new labels.
You've created a chart with separate Deployment, Service, and ConfigMap. Each has duplicate labels, annotations, and image pull secret handling. Your job is to refactor common patterns into _helpers.tpl and simplify your manifests.
Files to work with:
Show AI your current manifests:
Based on AI's suggestions, ask:
Ask AI to help you validate:
Show AI your refactored manifests:
Verify your work:
Compare the output:
Check your helpers are used everywhere they should be:
Should show calls in deployment, service, configmap—not in _helpers.tpl definitions.
You built a helm-chart skill in Lesson 0. Test and improve it based on what you learned.
Ask yourself:
If you found gaps: