define, template & include
define creates a named template; template and include insert it — include is preferred because it can be piped.
{{ include "mychart.labels" . | nindent 4 }}Three keywords work together for reusable snippets.
define
Declares a named template block (usually in _helpers.tpl).
template
The built-in action {{ template "name" . }} inserts a named template's output directly. The trailing . passes the current context so the template can read .Values etc.
include
{{ include "name" . }} does the same but returns a string instead of writing directly. That means you can pipe it — for example through nindent to fix indentation. Prefer include for this reason.
Example
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}When to use it
- A developer uses include instead of template so the output of a named template can be piped through nindent to align it correctly inside a parent YAML block.
- A chart author defines a shared selector-labels template and includes it in both the Deployment's matchLabels and the Service's selector to guarantee they stay in sync.
- A library chart exposes named templates via define so consuming charts can include common resource patterns without copying any YAML.
More examples
define and include basic
Defines a standard labels block as a named template that any manifest can include rather than duplicating the same four lines.
{{/* _helpers.tpl */}}
{{- define "myapp.labels" -}}
app.kubernetes.io/name: {{ include "myapp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}include vs template
Shows why include is preferred over template: its return value can be piped through nindent to control indentation.
# Prefer include because it returns a string you can pipe
metadata:
labels:
{{- include "myapp.labels" . | nindent 4 }}
# template cannot be piped
# {{- template "myapp.labels" . }} <- no pipeline supportPass custom context to helper
Passes a subset of .Values as the context to a named template, allowing the helper to be called with different image configs.
{{- define "myapp.image" -}}
{{- printf "%s:%s" .repository (.tag | default "latest") }}
{{- end }}
# In a template:
image: {{ include "myapp.image" .Values.image }}
Discussion