Template Helpers
A comprehensive guide to Helm template helpers covering _helpers.tpl, named templates, include vs template functions, and best practices for reusable Helm templates.
Template helpers are reusable template functions defined in _helpers.tpl files. They help avoid code duplication and keep templates clean and maintainable.
Helpers are defined using the define action and can be used across multiple templates.
_helpers.tpl is a special file in the templates/ directory that contains reusable template definitions. It does not produce any output on its own.
# templates/_helpers.tpl
{{- define "my-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- define "my-app.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{- define "my-app.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- define "my-app.labels" -}}
helm.sh/chart: {{ include "my-app.chart" . }}
{{ include "my-app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{- define "my-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{- define "my-app.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "my-app.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{- define "my-app.imagePullSecrets" -}}
{{- if .Values.image.pullSecrets }}
imagePullSecrets:
{{- toYaml .Values.image.pullSecrets | nindent 2 }}
{{- end }}
{{- end }}
{{- define "my-app.resources" -}}
resources:
{{- toYaml .Values.resources | nindent 2 }}
{{- end }}
{{- define "my-app.environment" -}}
{{ .Values.environment | default "production" }}
{{- end }}
name
fullname
labels
selectorLabels
serviceAccountName
imagePullSecrets
- Use
defineto create reusable functions - Prefix helper names with chart name to avoid conflicts
- Use
includeto call other helpers - Keep helpers focused and single-purpose
- Document complex helpers with comments
- Use
truncandtrimSuffixfor name length limits
Named templates are defined using define and called using include or template.
# Defining a named template
{{- define "my-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
# Using a named template with include
{{ include "my-app.name" . }}
# Using a named template with template
{{ template "my-app.name" . }}
# Named template with parameters
{{- define "my-app.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
# Named template with multiple lines
{{- define "my-app.labels" -}}
helm.sh/chart: {{ include "my-app.chart" . }}
{{ include "my-app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
# Nested helpers
{{- define "my-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
# Helper with conditional logic
{{- define "my-app.ingressPath" -}}
{{- if .Values.ingress.path }}
{{ .Values.ingress.path }}
{{- else }}
/
{{- end }}
{{- end }}
my-app.name) to avoid name collisions when charts are used as subcharts.
include
template
# Using include (recommended)
{{ include "my-app.labels" . }}
# Using include in a pipeline
{{ include "my-app.labels" . | indent 4 }}
# Using include with nindent
{{- include "my-app.labels" . | nindent 4 }}
# Using include with toYaml
{{- include "my-app.resources" . | toYaml | nindent 2 }}
# Using include in a conditional
{{ if .Values.ingress.enabled }}
{{ include "my-app.ingress" . }}
{{ end }}
# Using template (limited usage)
{{ template "my-app.name" . }}
# template cannot be used in pipelines
# This will NOT work:
{{ template "my-app.name" . | indent 4 }}
# This WILL work (using include):
{{ include "my-app.name" . | indent 4 }}
# include with default
{{ include "my-app.fullname" . | default "default-name" }}
# include with quote
{{ include "my-app.name" . | quote }}
# include with trunc
{{ include "my-app.fullname" . | trunc 63 }}
include instead of template because:
includecan be used in pipelinesincludereturns a string (more flexible)includesupports chaining with other functionsincludeis the preferred pattern in modern Helm
# 1. Name generation with fallbacks
{{- define "my-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
# 2. Full name with release name
{{- define "my-app.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
# 3. Labels with consistent structure
{{- define "my-app.labels" -}}
helm.sh/chart: {{ include "my-app.chart" . }}
{{ include "my-app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
# 4. Selector labels for services
{{- define "my-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
# 5. Conditional blocks
{{- define "my-app.ingress" -}}
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "my-app.fullname" . }}
labels:
{{- include "my-app.labels" . | nindent 4 }}
annotations:
{{- toYaml .Values.ingress.annotations | nindent 4 }}
spec:
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "my-app.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
# 6. Resource formatting
{{- define "my-app.resources" -}}
{{- if .Values.resources }}
resources:
{{- toYaml .Values.resources | nindent 2 }}
{{- end }}
{{- end }}
# 7. Environment variable helpers
{{- define "my-app.env" -}}
{{- range $key, $value := .Values.extraEnv }}
- name: {{ $key | quote }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
- Use
defaultfor fallback values - Use
truncandtrimSuffixfor name length limits - Use
includeto compose helpers - Keep helpers focused and single-purpose
- Use
withfor optional blocks - Use
rangefor loops
# Debug helper to inspect values
{{- define "my-app.debug" -}}
{{- printf "Values: %v" .Values | nindent 0 }}
{{- end }}
# Use debug helper in template
{{ include "my-app.debug" . }}
# Helper to check if a value exists
{{- define "my-app.hasValue" -}}
{{- if .Values.key }}
{{- true }}
{{- else }}
{{- false }}
{{- end }}
{{- end }}
# Helper to print variable
{{- define "my-app.printVar" -}}
{{- printf "Variable: %s" . | nindent 0 }}
{{- end }}
# Dry-run to see rendered helpers
helm template my-release ./my-chart --debug | grep -A 5 "my-app"
# Check helper syntax
helm lint ./my-chart
# Render specific helper
helm template my-release ./my-chart --debug | grep -A 10 "my-app.name"
_helpers.tpl is a special file in the templates/ directory that contains reusable template definitions. It does not produce any output on its own.include returns the template output as a string and can be used in pipelines. template renders directly and cannot be used in pipelines. Always use include.my-app.name) to avoid name collisions when charts are used as subcharts.include. This enables composition and code reuse.templates/_helpers.tpl. This is the standard location for reusable template definitions.include with the chart name prefix.helm template --debug to see rendered output. Add temporary printf statements in helpers for debugging. Use helm lint for syntax checking. Template helpers are essential for creating maintainable Helm charts. Use _helpers.tpl to define reusable functions and always prefer include over template for flexibility.