helm template
pass variables
Kubernetes
Helm chart
DevOps

Pass multiple variables in helm template

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

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

yaml
1# values.yaml
2replicaCount: 3
3image:
4  repository: nginx
5  tag: "1.25"
6  pullPolicy: IfNotPresent
7service:
8  type: ClusterIP
9  port: 80
10database:
11  host: postgres.default.svc
12  port: 5432
13  name: myapp
14  credentials:
15    username: admin
16    password: secret123
yaml
1# templates/deployment.yaml
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5  name: {{ .Release.Name }}-app
6spec:
7  replicas: {{ .Values.replicaCount }}
8  template:
9    spec:
10      containers:
11        - name: app
12          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
13          imagePullPolicy: {{ .Values.image.pullPolicy }}
14          ports:
15            - containerPort: {{ .Values.service.port }}
16          env:
17            - name: DB_HOST
18              value: {{ .Values.database.host | quote }}
19            - name: DB_PORT
20              value: {{ .Values.database.port | quote }}
21            - name: DB_NAME
22              value: {{ .Values.database.name | quote }}

Overriding with --set

bash
1# Override single values
2helm install myrelease ./mychart --set replicaCount=5
3
4# Override nested values with dot notation
5helm install myrelease ./mychart \
6  --set image.tag="2.0" \
7  --set database.host="db.prod.svc"
8
9# Override multiple values in one --set
10helm install myrelease ./mychart \
11  --set replicaCount=5,service.port=8080
12
13# Set string values explicitly (useful for numeric strings)
14helm install myrelease ./mychart --set-string image.tag="1.25"
15
16# Override with array values
17helm install myrelease ./mychart \
18  --set "ingress.hosts[0].host=example.com" \
19  --set "ingress.hosts[0].paths[0].path=/"

Using Custom Values Files

yaml
1# values-production.yaml
2replicaCount: 5
3image:
4  tag: "1.25-stable"
5database:
6  host: postgres-prod.database.svc
7  credentials:
8    username: prod_admin
9resources:
10  requests:
11    memory: 512Mi
12    cpu: 500m
13  limits:
14    memory: 1Gi
15    cpu: 1000m
bash
1# Use default values.yaml + production overrides
2helm install myrelease ./mychart -f values-production.yaml
3
4# Stack multiple values files (later files override earlier ones)
5helm install myrelease ./mychart \
6  -f values.yaml \
7  -f values-production.yaml \
8  -f values-secrets.yaml
9
10# Combine files with --set (--set takes highest priority)
11helm install myrelease ./mychart \
12  -f values-production.yaml \
13  --set image.tag="hotfix-1.25.1"

Passing Variables Between Templates

Using include with Context

yaml
1# templates/_helpers.tpl
2{{- define "mychart.labels" -}}
3app.kubernetes.io/name: {{ .name }}
4app.kubernetes.io/instance: {{ .release }}
5app.kubernetes.io/version: {{ .version }}
6{{- end }}
yaml
1# templates/deployment.yaml
2metadata:
3  labels:
4    {{- include "mychart.labels" (dict "name" .Chart.Name "release" .Release.Name "version" .Chart.AppVersion) | nindent 4 }}

Using dict to Pass Multiple Variables

yaml
1# Pass a custom dictionary to a template
2{{- define "mychart.container" -}}
3- name: {{ .name }}
4  image: "{{ .image }}:{{ .tag }}"
5  ports:
6    - containerPort: {{ .port }}
7{{- end }}
8
9# Call it with a dict
10containers:
11  {{- include "mychart.container" (dict "name" "web" "image" .Values.image.repository "tag" .Values.image.tag "port" 8080) | nindent 8 }}

Using $ to Access Root Context

Inside range loops, the context (.) changes. Use $ to access the root context.

yaml
1# templates/configmap.yaml
2apiVersion: v1
3kind: ConfigMap
4metadata:
5  name: {{ $.Release.Name }}-config
6data:
7  {{- range $key, $value := .Values.config }}
8  {{ $key }}: {{ $value | quote }}
9  {{- end }}

Variable Assignment in Templates

yaml
1# Assign variables with $varName
2{{- $fullName := printf "%s-%s" .Release.Name .Chart.Name -}}
3{{- $port := .Values.service.port | default 80 -}}
4
5metadata:
6  name: {{ $fullName }}
7spec:
8  ports:
9    - port: {{ $port }}

Common Pitfalls

  • Forgetting to quote string values: YAML interprets unquoted values like true, false, null, and numbers automatically. Use {{ .Values.tag | quote }} or --set-string to ensure values are treated as strings. Without quoting, tag: "1.0" becomes the float 1 in YAML.
  • --set priority confusion: Values cascade in order: values.yaml (lowest) < -f custom.yaml < --set (highest). Later sources override earlier ones. This means --set always wins, which can be confusing when debugging why a values file override is not taking effect.
  • Losing root context in range loops: Inside {{ range .Values.items }}, the dot (.) refers to the current item, not the root context. Accessing .Release.Name inside the loop fails. Use $.Release.Name to access the root context.
  • Not using nindent for included templates: include returns the template output as a string. Without | nindent N, the included YAML is not properly indented, causing invalid Kubernetes manifests. Always pipe to nindent with the correct indentation level.
  • Passing the wrong context to include: include "mychart.labels" . passes the current context. If called inside a range loop, . is the loop item, not the root. Use include "mychart.labels" $ or construct a dict with the specific values needed.

Summary

  • Access variables in templates via {{ .Values.key }} from values.yaml
  • Override with --set key=value (highest priority) or -f custom-values.yaml
  • Use dict to pass multiple named variables to include template functions
  • Use $ to access root context inside range loops
  • Always quote string values with | quote to prevent YAML type coercion

Course illustration
Course illustration

All Rights Reserved.