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 -}}
ConventionReason
Live in _*.tpl filesUnderscore prefix prevents Helm from rendering as manifest
Namespace by chart nameAvoid collisions in subcharts: {{ define "myapp.x" }}

2. Including Templates

FunctionPipeableNotes
include "name" .YesReturns string; can chain with nindent / toYaml
template "name" .NoRenders 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

CallScope inside template
include "x" .Full root context (recommended)
include "x" .Values.fooSub-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 selectorsReason
Selectors are immutableDeployment/StatefulSet selector cannot change after creation
Drop chart/version labelsAvoids 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

HelperOutput
myapp.nameChart name (overridable)
myapp.fullname<release>-<name>, truncated to 63
myapp.serviceAccountNameConditional: 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.
PatternImplementation
Base + overridesLibrary chart defines base; consumer overrides via tpl or value-driven blocks
MixinsMultiple include calls composing into final YAML
tpl functionRender value as template — lets consumers inject snippets