Lesson 3 · Helm fundamentals

Templates & the Go engine

How {{ .Values.x }} becomes YAML — the objects, functions, and pipelines you'll actually read.

Your win: read a Helm template — the built-in objects (.Values / .Release / .Chart / .Capabilities), functions and pipelines, and the whitespace/indent idioms — using real lines from this repo.

Templates are Go templates that emit YAML

Each file in templates/ is a Go text/template. Actions live in {{ }}; everything else is passed through literally. Helm renders each file, then hands the resulting YAML to Kubernetes.1

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "util.fullname" . }}
  labels: {{- include "util.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount | default 2 }}

Built-in objects — the data you template from

ObjectHolds
.Valuesthe merged values (defaults + overrides)
.Release.Name, .Namespace, .IsUpgrade, .Revision
.Chartthe Chart.yaml fields (.Name, .Version)
.Capabilitiescluster/API info — e.g. .APIVersions.Has "keda.sh/v1alpha1"
.Filesaccess to non-template files in the chart
Anchor — all four, live in the library

Functions & pipelines

Helm ships Go template functions plus the Sprig library. You chain them with pipelines (|), left to right:2

IdiomDoes
{{ .Values.x | default "y" }}fall back if unset
{{ toYaml .Values.resources | nindent 4 }}serialize a block & indent it
{{ include "t" . | nindent 4 }}render a named template, indent
{{ tpl $str . }}render a string as a template
{{ required "msg" .Values.x }}fail the render if unset
Two idioms you'll see everywhere Whitespace control: {{- trims preceding whitespace, -}} trailing — essential because YAML is indentation-sensitive. toYaml | nindent N: turn a values block into YAML and indent it to the right column. Get nindent wrong and you get an invalid-YAML error — the single most common Helm bug.
Anchor — the repo's power-idioms This codebase leans on advanced Sprig: _deployment.tpl:23-25 does fromYaml (include "_util.deployment.spot" .) then mustMergeOverwrite with an on-demand override and toYaml back out — i.e. it renders one Deployment, deep-merges a patch, and re-emits it (Course 2 L10's spot/on-demand nodes). For validation it prefers fail over required (_check.tpl:44).
include vs template — pick include Both render a named template. include returns a string you can pipe (| nindent 4); template is a bare action that can't be piped. That's why every call here is include.
Read this next

Helm docs — Built-in Objects + Functions and Pipelines

The full object list, the function/Sprig reference, and the whitespace & indent rules.

helm.sh — Built-in Objects
helm.sh — Functions & Pipelines

Check yourself (from memory)

Q1. .Release.Namespace gives you…

.Release.* describes the install; the repo bakes it into the KEDA Prometheus query to scope metrics.

Q2. toYaml .Values.resources | nindent 4 is used to…

Turn a values map into YAML, indented to the right column. Wrong indent is the classic Helm error.

Q3. You prefer include over template because…

include returns a string you can pipe; template is an action that can't be piped.
Built-in objects, the key pipeline idioms, and include-vs-template.
recall, then click to reveal
Templates are GO TEMPLATES emitting YAML; actions in {{ }}. BUILT-IN OBJECTS: .Values (merged config), .Release (Name/Namespace/IsUpgrade/Revision), .Chart (Chart.yaml fields), .Capabilities (e.g. .APIVersions.Has "keda.sh/v1alpha1"), .Files. FUNCTIONS/PIPELINES (Go + Sprig): default, toYaml | nindent N (serialize + indent — wrong indent = the classic bug), tpl (render a string as a template), required/fail, fromYaml/mustMergeOverwrite. Whitespace: {{- / -}} trim. INCLUDE vs TEMPLATE: include returns a pipeable string (use it); template can't be piped. Repo idiom: fromYaml→mustMergeOverwrite→toYaml for spot/on-demand merge (_deployment.tpl:23-25).
Want to see if/range/with and scoping (the . context), or debug an nindent mistake together? Ask me.

1. Helm — Built-in Objects.

2. Helm — Functions and Pipelines.