Templating
Zarf supports Go template syntax and text/template engine with powerful features including control flow and functions. Zarf includes the full library of Sprig functions and some builtins for dynamic configuration in manifests, files, and actions. This powerful templating system enables complex transformations, conditional logic, and data manipulation beyond simple string substitution.
To use Zarf templates, it’s important to understand template objects. Template objects contain data that you can access in your templates. They always start with a capital letter.
Most commonly, Package Values files allow you to define and access your own data:
{{ .Values.app.name }}{{ .Values.database.host }}{{ .Values.site.organization }}Example in a manifest:
apiVersion: v1kind: ConfigMapmetadata: name: {{ .Values.app.name }}-configdata: environment: {{ .Values.app.environment }} replicas: "{{ .Values.app.replicas }}"Fields from the package definition’s metadata are available in all templates:
{{ .Metadata.name }} # Package name{{ .Metadata.description }} # Package description{{ .Metadata.version }} # Package versionExample in a manifest:
apiVersion: v1kind: ConfigMapmetadata: name: package-infodata: package-name: {{ .Metadata.name }} package-version: {{ .Metadata.version }}Similar to Metadata, Build fields on the package definition can be accessed during deploy and remove:
{{ .Build.timestamp }} # Build timestamp{{ .Build.architecture }} # Target architecture (e.g., amd64, arm64){{ .Build.version }} # Zarf version used to buildExample in a manifest:
apiVersion: v1kind: ConfigMapmetadata: name: build-info annotations: build-time: {{ .Build.timestamp }} target-arch: {{ .Build.architecture }}If users want to start using the new templates before switching over to Values, Variables and Constants are also available.
{{ .Variables.EXAMPLE_VAR }}{{ .Constants.EXAMPLE_CONST }}Use double curly braces to insert values from template objects:
# Simple value insertionname: {{ .Values.app.name }}
# Nested values with dot notationhost: {{ .Values.database.host }}port: {{ .Values.database.port }}
# Accessing different template objectspackageName: {{ .Metadata.name }}buildTime: {{ .Build.timestamp }}Control whitespace around template expressions:
# Remove leading whitespace{{- .Values.app.name }}
# Remove trailing whitespace{{ .Values.app.name -}}
# Remove both{{- .Values.app.name -}}Enable templating in manifest files by setting template: true:
components: - name: my-component manifests: - name: k8s-resources template: true # Enables Go template processing files: - deployment.yaml - service.yaml - configmap.yamlExample templated manifest:
apiVersion: apps/v1kind: Deploymentmetadata: name: {{ .Values.app.name }} labels: app: {{ .Values.app.name }} environment: {{ .Values.app.environment }}spec: replicas: {{ .Values.app.replicas }} selector: matchLabels: app: {{ .Values.app.name }} template: metadata: labels: app: {{ .Values.app.name }} spec: containers: - name: {{ .Values.app.name }} image: {{ .Values.app.image }}:{{ .Values.app.tag }}Action templating must be enabled to help avoid conflicts with external tools. Set template: true on individual actions:
components: - name: my-component actions: onCreate: after: # Templating enabled - cmd: | echo "Building {{ .Values.app.name }}" echo "Version: {{ .Values.app.version }}" template: true
# Templating disabled (default) - cmd: | # This {{ .template }} syntax is preserved envsubst < template.yamlWhy opt-in for actions?
- Prevents conflicts with shell variables like
${VAR} - Avoids breaking external tools that use
{{ }}syntax (e.g., envsubst, gomplate) - Provides explicit control over when Zarf processes templates
Templating is also available in remove actions:
components: - name: my-component actions: onRemove: before: - cmd: | echo "Removing {{ .Values.site.name }}" echo "Environment: {{ .Values.app.environment }}" echo "Organization: {{ .Values.site.organization }}" template: trueZarf includes both builtin functions and the full Sprig template function library, providing powerful data transformation capabilities. See the values-templating example for comprehensive demonstrations of all function categories.
Transform and manipulate strings with functions like upper, lower, title, kebabcase, snakecase, quote, trim, and more:
# Case and format conversionname: {{ .Values.app.name | upper }} # MY-APPname: {{ .Values.site.title | kebabcase }} # my-awesome-appvalue: {{ .Values.app.name | quote }} # "my-app"
# Trimming and manipulationmessage: {{ .Values.message | trim }}short: {{ .Values.longText | trunc 50 }}See the values-templating example for more string function examples.
Work with arrays and lists using functions like join, len, first, last, sortAlpha, reverse, and has:
features: {{ .Values.app.features | join ", " }}count: {{ .Values.app.features | len }}first: {{ .Values.app.features | first }}sorted: {{ .Values.app.features | sortAlpha | join ", " }}See the values-templating example for more list function examples.
Provide fallback values using functions like default, empty, coalesce, and ternary:
replicas: {{ .Values.app.replicas | default 3 }}namespace: {{ .Values.app.namespace | default "default" }}host: {{ coalesce .Values.database.host .Values.database.defaultHost "localhost" }}environment: {{ .Values.app.production | ternary "prod" "dev" }}Perform arithmetic operations using add, sub, mul, div, max, min, round, and more:
sum: {{ add .Values.app.replicas 2 }}product: {{ mul .Values.app.replicas 10 }}max-port: {{ max .Values.app.port1 .Values.app.port2 .Values.app.port3 }}See the values-templating example for more math function examples.
Encode data and generate hashes using b64enc, b64dec, sha256sum, sha1sum, and more:
encoded: {{ .Values.app.secret | b64enc }}sha256: {{ .Values.app.data | sha256sum }}Common use case for Secrets:
apiVersion: v1kind: Secrettype: Opaquedata: username: {{ .Values.database.username | b64enc }} password: {{ .Values.database.password | b64enc }}See the values-templating example for more encoding examples.
Format and indent output using indent, nindent, toString, toYaml, toJson, and more:
# Indentation{{ .Values.multilineConfig | indent 4 }}
# Type conversionport: {{ .Values.app.port | toString }}
# Multi-line values in ConfigMapsdata: config.yaml: |{{ .Values.app.config | toYaml | indent 4 }}Go’s text/template engine allows the use of if/else statements for conditional rendering:
apiVersion: v1kind: ConfigMapmetadata: name: app-configdata: {{ if .Values.app.production }} environment: "production" log-level: "warn" {{ else }} environment: "development" log-level: "debug" {{ end }}
{{ if eq .Values.app.environment "production" }} replicas: "3" {{ else if eq .Values.app.environment "staging" }} replicas: "2" {{ else }} replicas: "1" {{ end }}# Equality{{ if eq .Values.app.environment "production" }}{{ if ne .Values.app.environment "production" }} # not equal
# Numeric comparisons{{ if gt .Values.app.replicas 3 }} # greater than{{ if ge .Values.app.replicas 3 }} # greater or equal{{ if lt .Values.app.replicas 3 }} # less than{{ if le .Values.app.replicas 3 }} # less or equal
# Logical operators{{ if and .Values.app.production .Values.app.secure }}{{ if or .Values.app.debug .Values.app.verbose }}{{ if not .Values.app.production }}Go’s text/template engine also allows users to iterate over lists and maps:
# Iterating over a list{{ range .Values.app.features }} - {{ . }}{{ end }}
# With index{{ range $index, $feature := .Values.app.features }} {{ $index }}: {{ $feature }}{{ end }}
# Iterating over a map{{ range $key, $value := .Values.app.config }} {{ $key }}: {{ $value }}{{ end }}Example in a ConfigMap:
apiVersion: v1kind: ConfigMapmetadata: name: features-configdata: features.txt: | Enabled features:{{ range .Values.app.features }} - {{ . }}{{ end }}
ports.conf: |{{ range $index, $port := .Values.app.ports }} listen {{ $port }};{{ end }}Assign values to go template variables for reuse within a template (note, :
{{ $appName := .Values.app.name }}{{ $namespace := .Values.app.namespace | default "default" }}
apiVersion: v1kind: Servicemetadata: name: {{ $appName }}-service namespace: {{ $namespace }}spec: selector: app: {{ $appName }}For comprehensive examples combining multiple template functions, see the values-templating example which demonstrates:
- String transformations (upper, lower, kebabcase, title)
- List operations (join, len, first, sortAlpha)
- Default values and conditionals
- Math operations (add, mul, max, min)
- Encoding and hashing (b64enc, sha256sum)
- Multi-line values with indentation
- Real-world ConfigMap and Deployment examples
- Helm templating happens inside chart templates (standard Helm behavior)
- Zarf templating happens at the package level
- Use Helm value mappings to pass Zarf values to charts
- Templating Best Practices - Best practices for templating
- Package Values - Defining and using package values
- Actions - Templating in component actions
- Deployment Values (Legacy) - Legacy templating system
- Sprig Function Documentation - Complete Sprig reference