Pass multiple variables in helm template
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Helm templates use Go's text/template engine to render Kubernetes manifests dynamically. Variables come from values.yaml (defaults), --set flags (overrides), and custom values files (-f custom.yaml). Passing multiple variables involves accessing them through the .Values object in templates, using --set for individual overrides, and using custom values files for environment-specific configurations. For passing variables between templates and helper functions, Helm uses the dict, list, and include functions.
Passing Variables via values.yaml
Overriding with --set
Using Custom Values Files
Passing Variables Between Templates
Using include with Context
Using dict to Pass Multiple Variables
Using $ to Access Root Context
Inside range loops, the context (.) changes. Use $ to access the root context.
Variable Assignment in Templates
Common Pitfalls
- Forgetting to quote string values: YAML interprets unquoted values like
true,false,null, and numbers automatically. Use{{ .Values.tag | quote }}or--set-stringto ensure values are treated as strings. Without quoting,tag: "1.0"becomes the float1in YAML. --setpriority confusion: Values cascade in order:values.yaml(lowest) <-f custom.yaml<--set(highest). Later sources override earlier ones. This means--setalways wins, which can be confusing when debugging why a values file override is not taking effect.- Losing root context in
rangeloops: Inside{{ range .Values.items }}, the dot (.) refers to the current item, not the root context. Accessing.Release.Nameinside the loop fails. Use$.Release.Nameto access the root context. - Not using
nindentfor included templates:includereturns the template output as a string. Without| nindent N, the included YAML is not properly indented, causing invalid Kubernetes manifests. Always pipe tonindentwith the correct indentation level. - Passing the wrong context to
include:include "mychart.labels" .passes the current context. If called inside arangeloop,.is the loop item, not the root. Useinclude "mychart.labels" $or construct adictwith the specific values needed.
Summary
- Access variables in templates via
{{ .Values.key }}fromvalues.yaml - Override with
--set key=value(highest priority) or-f custom-values.yaml - Use
dictto pass multiple named variables toincludetemplate functions - Use
$to access root context insiderangeloops - Always quote string values with
| quoteto prevent YAML type coercion
Related reading
- Pass postgres parameter into Kubernetes deployment
- Pass statefulset's replica count to it's pod
- Passing JVM args to Docker image of Spring boot app on Kubernetes
- Passing long configuration file to Kubernetes
- Passing separate env variables to statefulset pods
- Pathway/road laying problem
- PersistentVolume does not use local host path
- PersistentVolumeClaim is stuck ''waiting for a volume to be created, either by external provisioner ebs.csi.aws.com'' on new AWS EKS cluster

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.