Large chart estates and platform teams rely on these to stay DRY and correct.
Powerful functions, each with a catch:
lookup "v1" "Secret" .Release.Namespace "shop-db"reads a live object during rendering, e.g. to keep a generated password stable across upgrades instead of regenerating it. It returns an empty map underhelm templateand client-side dry runs (no cluster access), so templates must handle that case, and it makes rendering depend on cluster state, which GitOps tools often can't provide.tpl .Values.annotationsTemplate .renders a value string as a template, so users can write{{ .Release.Name }}inside values. Handy for chart authors, but it's easy to make values unreadable.fail "message"andrequiredstop rendering with a clear error when values are inconsistent (ingress enabled with no hosts).dict,list,merge,mergeOverwrite,deepCopy,toJson,fromYamllet helpers take structured arguments and build objects.
Library charts (type: library in Chart.yaml) contain only named templates and can't be installed. Application charts depend on one and call its helpers, e.g. {{ include "common.deployment" (dict "root" . "name" "api") }}. Platform teams use this to give dozens of services identical labels, probes and security contexts while each service chart stays tiny.
Keep charts boring: templating everything is the road to an unmaintainable chart. If you need real logic, consider generating manifests with a proper language or using an operator.
Example
{{/* Keep a generated password stable across upgrades */}}
{{- $existing := lookup "v1" "Secret" .Release.Namespace (printf "%s-db" .Release.Name) }}
{{- $pw := "" }}
{{- if $existing }}
{{- $pw = index $existing.data "password" | b64dec }}
{{- else }}
{{- $pw = randAlphaNum 24 }}
{{- end }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Release.Name }}-db
annotations:
{{- tpl (toYaml .Values.extraAnnotations) . | nindent 4 }}
stringData:
password: {{ $pw | quote }}
{{- if and .Values.ingress.enabled (not .Values.ingress.hosts) }}
{{- fail "ingress.enabled requires at least one ingress.hosts entry" }}
{{- end }}Remember
- lookup reads live objects but is empty during helm template
- tpl renders values as templates; fail/required give clear errors
- Library charts share helpers across many service charts
Watch out for
- Relying on lookup in a chart deployed by a GitOps tool that renders without cluster access, regenerating secrets each time.