Working with Named Templates
1. Defining Named Templates
Example: Define block
{{- define "myapp.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
| Convention | Reason |
Live in _*.tpl files | Underscore prefix prevents Helm from rendering as manifest |
| Namespace by chart name | Avoid collisions in subcharts: {{ define "myapp.x" }} |
2. Including Templates
| Function | Pipeable | Notes |
include "name" . | Yes | Returns string; can chain with nindent / toYaml |
template "name" . | No | Renders inline; cannot pipe |
3. Using Template Directive
Example: include vs template
labels:
{{- include "myapp.labels" . | nindent 2 }} # GOOD: piped/indented
# template works but cannot pipe output:
{{ template "myapp.labels" . }}
4. Creating Partial Templates
Example: Reusable selector labels
{{- define "myapp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "myapp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
5. Passing Scope to Templates
| Call | Scope inside template |
include "x" . | Full root context (recommended) |
include "x" .Values.foo | Sub-scope only — careful with .Release access |
include "x" (dict "Values" .Values "extra" "v") | Custom scope dict |
6. Defining Common Labels
Example: Standard label set
{{- define "myapp.labels" -}}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 }}
{{ include "myapp.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
7. Creating Selector Templates
| Why separate selectors | Reason |
| Selectors are immutable | Deployment/StatefulSet selector cannot change after creation |
| Drop chart/version labels | Avoids selector churn on chart upgrades |
8. Building Image Strings
Example: Image helper supporting registry + digest
{{- define "myapp.image" -}}
{{- $reg := .Values.image.registry | default .Values.global.imageRegistry -}}
{{- $repo := .Values.image.repository -}}
{{- $tag := .Values.image.tag | default .Chart.AppVersion -}}
{{- if .Values.image.digest -}}
{{- printf "%s/%s@%s" $reg $repo .Values.image.digest -}}
{{- else -}}
{{- printf "%s/%s:%s" $reg $repo $tag -}}
{{- end -}}
{{- end -}}
9. Generating Resource Names
| Helper | Output |
myapp.name | Chart name (overridable) |
myapp.fullname | <release>-<name>, truncated to 63 |
myapp.serviceAccountName | Conditional: fullname or override |
10. Reusing Template Logic
Example: Composition
metadata:
name: {{ include "myapp.fullname" . }}
labels: {{- include "myapp.labels" . | nindent 4 }}
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
11. Using Template Inheritance
Note: Go templates don't support classical inheritance. Achieve composition via include + dict to pass extension points.
| Pattern | Implementation |
| Base + overrides | Library chart defines base; consumer overrides via tpl or value-driven blocks |
| Mixins | Multiple include calls composing into final YAML |
tpl function | Render value as template — lets consumers inject snippets |