diff --git a/site/src/content/docs/best-practices/package-values.mdx b/site/src/content/docs/best-practices/package-values.mdx new file mode 100644 index 0000000000..9f382f2247 --- /dev/null +++ b/site/src/content/docs/best-practices/package-values.mdx @@ -0,0 +1,252 @@ +--- +title: Package Values +sidebar: + order: 10 +--- + +This guide provides best practices for using [Package Values](/ref/package-values/) in your Zarf packages. + +:::caution + +Package Values is currently an **alpha feature** and requires the `--features="values=true"` flag when creating, deploying, inspecting, or removing packages. + +::: + +## Organize Values Logically + +Group related values together using nested structures. This makes your values files easier to understand and maintain: + +```yaml +# values.yaml +app: + name: "my-app" + environment: "production" + replicas: 3 + +database: + host: "db.example.com" + port: 5432 + name: "appdb" + +monitoring: + enabled: true + retention: "30d" +``` + +## Use Meaningful Defaults + +Provide sensible defaults in your package values files that work out-of-the-box: + +```yaml +app: + replicas: 3 # Default for production + logLevel: "info" + resources: + limits: + cpu: "1000m" + memory: "512Mi" + +# Optional settings with safe defaults +features: + experimental: false + debug: false +``` + +## Separate Environment-Specific Values + +Use multiple values files for different environments: + +```yaml +# values.yaml (base configuration) +app: + name: "my-app" + replicas: 1 + +# values-production.yaml (production overrides) +app: + replicas: 3 + logLevel: "warn" + +# values-development.yaml (development overrides) +app: + replicas: 1 + logLevel: "debug" + features: + debug: true +``` + +Deploy with environment-specific values: + +```bash +# Production deployment +zarf package deploy my-package.tar.zst \ + --features="values=true" \ + -f values-production.yaml + +# Development deployment +zarf package deploy my-package.tar.zst \ + --features="values=true" \ + -f values-development.yaml +``` + +## Use Schema Validation + +Define a JSON schema to validate values and catch errors early: + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "app": { + "type": "object", + "properties": { + "replicas": { + "type": "integer", + "minimum": 1, + "maximum": 10, + "description": "Number of application replicas" + }, + "environment": { + "type": "string", + "enum": ["development", "staging", "production"], + "description": "Deployment environment" + }, + "logLevel": { + "type": "string", + "enum": ["debug", "info", "warn", "error"], + "default": "info" + } + }, + "required": ["replicas", "environment"] + } + }, + "required": ["app"] +} +``` + +Reference the schema in your package: + +```yaml +# zarf.yaml +values: + files: + - values.yaml + schema: values-schema.json +``` + +## Leverage Templating Functions + +Use [functions](/ref/templating/#template-functions) for dynamic configuration: + +```yaml +# In manifests with template: true +metadata: + name: {{ .Values.app.name | kebabcase }} + labels: + app: {{ .Values.app.name | kebabcase }} + environment: {{ .Values.app.environment | upper }} + version: {{ .Values.app.version | quote }} + +spec: + # Use defaults for optional values + replicas: {{ .Values.app.replicas | default 1 }} + + # Conditional configuration: + {{- if .Values.monitoring.enabled }} + annotations: + prometheus.io/scrape: "true" + {{- end }} +``` + +:::note +Conditionals are powerful but can quickly become confusing. If you find yourself needing complex conditionals, see if +you can instead express the problem with data. +::: + +See the [Templating Reference](/ref/templating/) for complete function documentation. + +## Do Not Commit Sensitive Values in Package + +Values are the best way to pass secrets into your Zarf package, but those secrets should not be baked into the values files a package is created with: + +```yaml +# values.yaml +# DO NOT DO THIS +database: + password: "super-secret-password" + apiKey: "sk-1234567890" +``` + +```yaml +# zarf.yaml +values: + files: + - values.yaml +``` + +Instead, pass secret values to Zarf on deploy or remove with `-v`, `--values`, or by declaring the files in `.zarf-config.yaml` + +```bash +zarf package deploy \ + --features="values=true" \ + -v production.yaml +``` + +or + +```yaml +# ~/.zarf-config.yaml +package: + deploy: + values: + - production.yaml +``` + +Or set the values directly with `--set-values`, +```bash +zarf package deploy \ + --features="values=true" \ + --set-values=".database.password=$(DB_PASSWORD)" + --set-values=".database.apiKey=$(DB_API_KEY)" +``` + +Secrets can also be retrieved dynamically using `actions` and `setValues`: + +```yaml +components: + - name: dynamic-secrets + actions: + onDeploy: + before: + - cmd: kubectl get secret db-creds -o jsonpath='{.data.password}' | base64 -d + setValues: + - name: database.password +``` + +## Test Your Values + +Use `zarf dev inspect manifests` to preview templated resources without deploying: + +```bash +# Test with default values +zarf dev inspect manifests --features="values=true" + +# Test with custom values +zarf dev inspect manifests \ + --features="values=true" \ + --values custom-values.yaml \ + --set-values="app.replicas=5" +``` + +This helps you: +- Verify templates render correctly +- Catch syntax errors before deployment +- Test different value combinations +- Review the final Kubernetes manifests + +## Related Documentation + +- [Package Values Reference](/ref/package-values/) - Complete Package Values documentation +- [Templating Reference](/ref/templating/) - Template syntax and functions +- [values-templating Example](https://github.com/defenseunicorns/zarf/tree/main/examples/values-templating) - Working examples diff --git a/site/src/content/docs/best-practices/templating.mdx b/site/src/content/docs/best-practices/templating.mdx new file mode 100644 index 0000000000..82cd21a37b --- /dev/null +++ b/site/src/content/docs/best-practices/templating.mdx @@ -0,0 +1,241 @@ +--- +title: Templating +sidebar: + order: 11 +--- + +This guide provides best practices for using [templating](/ref/templating/) in your Zarf packages. + +:::caution + +Templating with Package Values is currently an **alpha feature** and requires the `--features="values=true"` flag when creating, deploying, inspecting, or removing packages. + +::: + +## Use Pipelines for Readability + +Chain functions together using the pipe operator (`|`) for clarity: + +```yaml +# Clear transformation pipeline +name: {{ .Values.app.name | lower | kebabcase | trunc 50 }} +``` + +## Always Quote String Values + +Use the `quote` function to ensure string values are properly quoted in YAML: + +```yaml +environment: {{ .Values.app.environment | quote }} +image: {{ .Values.app.image | quote }} +``` + +## Control Whitespace + +Use whitespace control operators (`-`) to manage output formatting: + +```yaml +# Clean output, no extra blank lines +{{- if .Values.app.debug }} +debug: true +{{- end }} + +# Produces unwanted blank lines +{{ if .Values.app.debug }} +debug: true +{{ end }} +``` + +**Whitespace control operators:** +- `{{-` removes whitespace before the template +- `-}}` removes whitespace after the template +- `{{- -}}` removes whitespace on both sides + +**Example output difference:** + +```yaml +# Without whitespace control: +metadata: + labels: + + app: nginx + +# With whitespace control: +metadata: + labels: + app: nginx +``` + +## Avoid Over-Templating + +Keep templates simple and prefer data over complex logic: + +```yaml +# Simple conditional +{{- if .Values.monitoring.enabled }} +annotations: + prometheus.io/scrape: "true" +{{- end }} + +# AVOID Complex nested logic +{{- if and .Values.monitoring.enabled (or (eq .Values.app.environment "production") (eq .Values.app.environment "staging")) (not .Values.app.debug) }} +annotations: + prometheus.io/scrape: "true" + prometheus.io/port: {{ .Values.monitoring.port | default 8080 | quote }} +{{- end }} +``` + +**Better approach for complex cases:** + +Move logic to values files: + +```yaml +# values.yaml +monitoring: + enabled: true + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8080" +``` + +```yaml +# manifest +{{- if .Values.monitoring.enabled }} +annotations: +{{- range $key, $value := .Values.monitoring.annotations }} + {{ $key }}: {{ $value | quote }} +{{- end }} +{{- end }} +``` + +## Use Template Variables for Reusability + +Define template variables to avoid repeating complex expressions: + +```yaml +# Define once, use many times +{{- $appName := .Values.app.name | lower | kebabcase -}} +{{- $namespace := .Values.app.namespace | default "default" -}} + +apiVersion: v1 +kind: Service +metadata: + name: {{ $appName }}-service + namespace: {{ $namespace }} +spec: + selector: + app: {{ $appName }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $appName }}-deployment + namespace: {{ $namespace }} +spec: + selector: + matchLabels: + app: {{ $appName }} + +# AVOID: Repeating the same expression +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.name | lower | kebabcase }}-service + namespace: {{ .Values.app.namespace | default "default" }} +spec: + selector: + app: {{ .Values.app.name | lower | kebabcase }} +``` + +## Handle Type Conversions Explicitly + +Convert types explicitly when needed: + +**Common conversions:** +- `toString` - Convert to string +- `toInt` - Convert to integer +- `toYaml` - Convert object to YAML +- `toJson` - Convert object to JSON + +## Test Templates Before Deployment + +Always preview your templates before deploying: + +```bash +# Preview manifests with default values +zarf dev inspect manifests --features="values=true" + +# Preview with custom values +zarf dev inspect manifests \ + --features="values=true" \ + -f custom-values.yaml + +# Preview with inline overrides +zarf dev inspect manifests \ + --features="values=true" \ + --set-values="app.replicas=5,app.environment=staging" +``` + +**What to check:** +- Templates render without errors +- Output looks as expected +- No unexpected whitespace +- Values are correctly interpolated +- Conditionals evaluate correctly + +## Common Errors and Solutions + +### Template Parse Errors + +**Error:** +``` +Error: template: :5:14: executing "" at <.Values.app.missing>: map has no entry for key "missing" +``` + +**Solution:** +```yaml +# Use default for optional values +value: {{ .Values.app.missing | default "fallback" }} +``` + +### Type Errors + +**Error:** +``` +Error: wrong type for value; expected string; got int +``` + +**Solution:** +```yaml +# Convert types explicitly +value: {{ .Values.app.port | toString | quote }} +``` + +### Whitespace Issues + +**Problem:** Extra blank lines or spacing in output + +**Solution:** +```yaml +# Use whitespace control operators +{{- if .Values.app.debug -}} +debug: true +{{- end -}} +``` + +### Quoting Problems + +**Problem:** YAML parsing fails with boolean-like strings + +**Solution:** +```yaml +# Always quote string values +value: {{ .Values.app.setting | quote }} +``` + +## Related Documentation + +- [Templating Reference](/ref/templating/) - Complete templating documentation +- [Package Values](/ref/package-values/) - Defining and using package values +- [Sprig Function Documentation](http://masterminds.github.io/sprig/) - Complete Sprig reference +- [values-templating Example](https://github.com/defenseunicorns/zarf/tree/main/examples/values-templating) - Working examples diff --git a/site/src/content/docs/ref/package-values.mdx b/site/src/content/docs/ref/package-values.mdx new file mode 100644 index 0000000000..edb4b07e8b --- /dev/null +++ b/site/src/content/docs/ref/package-values.mdx @@ -0,0 +1,424 @@ +--- +title: Package Values +sidebar: + order: 36 +--- + +import Properties from '@components/SchemaItemProperties.astro'; + +:::caution + +Package Values is currently an **alpha feature** and requires the `--features="values=true"` flag when creating, deploying, inspecting, or removing packages. The API may change in future releases. + +::: + +Package Values provide a familiar way to define reusable configuration data in your Zarf packages. Unlike the legacy [Variables and Constants](/ref/values/) system that uses string substitution with `###ZARF_VAR_###` syntax, Package Values uses Go templates with access to structured data and types, [go's templating engine](https://pkg.go.dev/text/template), and custom functions like those offered by [Sprig](/ref/templating/). + +## Overview + +Package Values allow you to: + +- Define structured configuration data in separate YAML files similar to [Helm's values files](https://helm.sh/docs/chart_template_guide/values_files/) +- Use Go template syntax (`{{ .Values.key }}`) for interpolation +- Leverage Go's templating engine for advanced transformations and use functions like [Sprig](/ref/templating/) +- Directly map Zarf package values to Helm chart values +- Maintain clean separation between configuration and deployment logic + +## Defining Values + +### Values Files + +Values are defined in YAML files and are declared in your `zarf.yaml` package configuration: + +```yaml +# zarf.yaml +kind: ZarfPackageConfig +metadata: + name: my-package +values: + files: + - values.yaml + - overrides.yaml + schema: values-schema.json # Optional JSON schema for validation +``` + +The values files contain structured YAML data: + +```yaml +# values/values.yaml +site: + name: "My Application" + organization: "MyOrg" + styles: | + body { font-family: sans-serif; } + +app: + environment: "production" + replicas: 3 + features: + - "templating" + - "sprig-functions" + ports: [80, 443, 8080] + +database: + host: "postgres.local" + port: 5432 +``` + +Multiple values files are merged in order, with later files taking precedence. + +### Schema Validation + +Optionally provide a JSON schema to validate user-provided values: + +```yaml +# zarf.yaml +values: + files: + - values.yaml + schema: values-schema.json +``` + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "app": { + "type": "object", + "properties": { + "replicas": { + "type": "integer", + "minimum": 1, + "maximum": 10 + }, + "environment": { + "type": "string", + "enum": ["development", "staging", "production"] + } + }, + "required": ["replicas", "environment"] + } + } +} +``` + +The schema validates values during deployment, helping catch configuration errors early. + +## Using Values + +Values are accessed in templates through the `.Values` template object. See the [Templating Reference](/ref/templating/#template-objects) for details on all available template objects (`.Values`, `.Metadata`, `.Build`, etc.). + +:::note + +Package Values are available during `onDeploy` and `onRemove` actions, but **not** during `onCreate` actions. This is because values are typically provided at deployment time, not package creation time. + +::: + +### In Manifests + +Enable Go templating in manifest files by setting `template: true`: + +```yaml +components: + - name: my-component + manifests: + - name: app-manifests + template: true # Enables Go template processing + files: + - deployment.yaml + - service.yaml + - configmap.yaml +``` + +See the [Templating Reference](/ref/templating/) for complete details on template syntax, Sprig functions, and advanced usage. + +### In Actions + +Actions require explicit opt-in to templating. Set `template: true` on individual actions: + +```yaml +components: + - name: my-component + actions: + onCreate: + after: + - cmd: | + echo "Deploying {{ .Values.site.name }}" + echo "Environment: {{ .Values.app.environment }}" + template: true # Required to enable templating in actions +``` + +See the [Templating Reference](/ref/templating/) for details on templating in actions and why it requires opt-in. + +#### Setting Values from Actions + +Actions can dynamically set values using the `setValues` field, similar to `setVariables`: + +```yaml +components: + - name: dynamic-config + actions: + onDeploy: + after: + - cmd: echo "generated-password-123" + setValues: + - name: database.password + + - cmd: kubectl get configmap app-config -o json + setValues: + - name: existing.config + type: json + + - cmd: | + cat < + +## Setting Values at Deploy Time + +Override or provide values when deploying or removing a package: + +### Using --set-values Flag + +Provide individual values via command line: + +```bash +# Set values at deploy time +zarf package deploy my-package.tar.zst \ + --features="values=true" \ + --set-values="app.environment=staging,app.replicas=5" + +# Set values during removal +zarf package remove my-package \ + --features="values=true" \ + --set-values="app.environment=staging" +``` + +### Using Values Files + +Provide entire values files with the `-v` or `--values` flag: + +```bash +# Deploy with custom values file +zarf package deploy my-package.tar.zst \ + --features="values=true" \ + -v custom-values.yaml + +# Multiple values files (later files override earlier ones) +zarf package deploy my-package.tar.zst \ + --features="values=true" \ + -v base-values.yaml \ + -v override-values.yaml + +# Also works with zarf dev deploy +zarf dev deploy \ + --features="values=true" \ + -v dev-values.yaml +``` + +### Configuration Files + +Values files can also be set in a Zarf config file: + +```yaml +# ~/.zarf-config.yaml +package: + deploy: + values: + - custom-values.yaml + remove: + values: + - cleanup-values.yaml +``` + +## Inspecting Values + +Zarf provides commands to inspect the results of values without having to deploy a package: + +```bash +# View the results of templates. This also works with command line and --set-values. +zarf dev inspect manifests --features="values=true" + +# View helm values files mappings +zarf package inspect values-files my-package.tar.zst --features="values=true" +``` + +## Migration from Variables and Constants + +If you're migrating from the legacy Variables/Constants system: + +### Before (Legacy) + +```yaml +# zarf.yaml +variables: + - name: DATABASE_USERNAME + default: "postgres" + +constants: + - name: APP_VERSION + value: "1.0.0" + +components: + - name: app + manifests: + - name: configmap + files: + - config.yaml +``` + +```yaml +# config.yaml +apiVersion: v1 +kind: ConfigMap +data: + username: ###ZARF_VAR_DATABASE_USERNAME### + version: ###ZARF_CONST_APP_VERSION### +``` + +### After (Package Values) + +```yaml +# zarf.yaml +values: + files: + - values.yaml + +components: + - name: app + manifests: + - name: configmap + template: true # Required for Go templates + files: + - config.yaml +``` + +```yaml +# values/values.yaml +database: + username: "postgres" + +app: + version: "1.0.0" +``` + +```yaml +# config.yaml +apiVersion: v1 +kind: ConfigMap +data: + username: {{ .Values.database.username }} + version: {{ .Values.app.version }} +``` + +**Benefits of the new approach:** +- Structured and typed data (numbers, booleans, arrays, objects) +- Access to powerful template engine and function chaining + +## Examples + +See the [values-templating example](/ref/examples/) for a complete working example demonstrating: + +- File-based values configuration +- Manifest templating with Go templates +- Helm chart value mappings +- Action templating +- Sprig function usage + +## Related Documentation + +- [Package Values Best Practices](/best-practices/package-values/) - Best practices for using Package Values +- [Templating Reference](/ref/templating/) - Complete guide to Go templates and Sprig functions +- [Deployment Values (Legacy)](/ref/values/) - Legacy Variables and Constants system +- [Actions](/ref/actions/) - Component action configuration +- [Components](/ref/components/) - Component structure and features diff --git a/site/src/content/docs/ref/templating.mdx b/site/src/content/docs/ref/templating.mdx new file mode 100644 index 0000000000..ff05f18d46 --- /dev/null +++ b/site/src/content/docs/ref/templating.mdx @@ -0,0 +1,445 @@ +--- +title: Templating +sidebar: + order: 37 +--- + +:::caution + +Templating with Package Values is currently an **alpha feature** and requires the `--features="values=true"` flag when creating, deploying, inspecting, or removing packages. + +::: + +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](http://masterminds.github.io/sprig/) 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. Zarf and Helm templates largely work the same, with similar custom functions as well, but they work on different layers. Zarf templates provide Zarf-specific template objects for actions and component items like manifests and files. + +## Template Objects + +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. + +### `.Values` + +Most commonly, [Package Values](/ref/package-values/) files allow you to define and access your own data: + +```yaml +{{ .Values.app.name }} +{{ .Values.database.host }} +{{ .Values.site.organization }} +``` + +Example in a manifest: +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.app.name }}-config +data: + environment: {{ .Values.app.environment }} + replicas: "{{ .Values.app.replicas }}" +``` + +### `.Metadata` + +Fields from the package definition's `metadata` are available in all templates: + +```yaml +{{ .Metadata.name }} # Package name +{{ .Metadata.description }} # Package description +{{ .Metadata.version }} # Package version +``` + +Example in a manifest: +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: package-info +data: + package-name: {{ .Metadata.name }} + package-version: {{ .Metadata.version }} +``` + +### `.Build` + +Similar to Metadata, Build fields on the package definition can be accessed during deploy and remove: + +```yaml +{{ .Build.timestamp }} # Build timestamp +{{ .Build.architecture }} # Target architecture (e.g., amd64, arm64) +{{ .Build.version }} # Zarf version used to build +``` + +Example in a manifest: +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: build-info + annotations: + build-time: {{ .Build.timestamp }} + target-arch: {{ .Build.architecture }} +``` + +### `.Variables` and `.Constants` + +If users want to start using the new templates before switching over to Values, Variables and Constants are also available. + +```yaml +{{ .Variables.EXAMPLE_VAR }} +{{ .Constants.EXAMPLE_CONST }} +``` + +## Template Syntax + +### Basic Interpolation + +Use double curly braces to insert values from template objects: + +```yaml +# Simple value insertion +name: {{ .Values.app.name }} + +# Nested values with dot notation +host: {{ .Values.database.host }} +port: {{ .Values.database.port }} + +# Accessing different template objects +packageName: {{ .Metadata.name }} +buildTime: {{ .Build.timestamp }} +``` + +### Whitespace Control + +Control whitespace around template expressions: + +```yaml +# Remove leading whitespace +{{- .Values.app.name }} + +# Remove trailing whitespace +{{ .Values.app.name -}} + +# Remove both +{{- .Values.app.name -}} +``` + +## Using Templates + +### Manifest Files + +Enable templating in manifest files by setting `template: true`: + +```yaml +components: + - name: my-component + manifests: + - name: k8s-resources + template: true # Enables Go template processing + files: + - deployment.yaml + - service.yaml + - configmap.yaml +``` + +Example templated manifest: + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + 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 }} +``` + +:::note + +Helm [chart hooks](https://helm.sh/docs/topics/charts_hooks/) are not templated by Zarf. + +::: + +### Actions + +Action templating must be enabled to help avoid conflicts with external tools. Set `template: true` on individual actions: + +```yaml +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.yaml +``` + +**Why 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 + +### Remove Actions + +Templating is also available in remove actions: + +```yaml +components: + - name: my-component + actions: + onRemove: + before: + - cmd: | + echo "Removing {{ .Values.site.name }}" + echo "Environment: {{ .Values.app.environment }}" + echo "Organization: {{ .Values.site.organization }}" + template: true +``` + +## Template Functions + +Zarf includes both builtin functions and the full [Sprig template function library](http://masterminds.github.io/sprig/), providing powerful data transformation capabilities. See the [values-templating example](/ref/examples/) for comprehensive demonstrations of all function categories. + +### String Functions + +Transform and manipulate strings with functions like `upper`, `lower`, `title`, `kebabcase`, `snakecase`, `quote`, `trim`, and more: + +```yaml +# Case and format conversion +name: {{ .Values.app.name | upper }} # MY-APP +name: {{ .Values.site.title | kebabcase }} # my-awesome-app +value: {{ .Values.app.name | quote }} # "my-app" + +# Trimming and manipulation +message: {{ .Values.message | trim }} +short: {{ .Values.longText | trunc 50 }} +``` + +See the [values-templating example](https://github.com/defenseunicorns/zarf/tree/main/examples/values-templating) for more string function examples. + +### List Functions + +Work with arrays and lists using functions like `join`, `len`, `first`, `last`, `sortAlpha`, `reverse`, and `has`: + +```yaml +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](https://github.com/defenseunicorns/zarf/tree/main/examples/values-templating) for more list function examples. + +### Default and Conditional Functions + +Provide fallback values using functions like `default`, `empty`, `coalesce`, and `ternary`: + +```yaml +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" }} +``` + +### Math Functions + +Perform arithmetic operations using `add`, `sub`, `mul`, `div`, `max`, `min`, `round`, and more: + +```yaml +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](https://github.com/defenseunicorns/zarf/tree/main/examples/values-templating) for more math function examples. + +### Encoding and Hashing Functions + +Encode data and generate hashes using `b64enc`, `b64dec`, `sha256sum`, `sha1sum`, and more: + +```yaml +encoded: {{ .Values.app.secret | b64enc }} +sha256: {{ .Values.app.data | sha256sum }} +``` + +Common use case for Secrets: +```yaml +apiVersion: v1 +kind: Secret +type: Opaque +data: + username: {{ .Values.database.username | b64enc }} + password: {{ .Values.database.password | b64enc }} +``` + +See the [values-templating example](https://github.com/defenseunicorns/zarf/tree/main/examples/values-templating) for more encoding examples. + +### Formatting Functions + +Format and indent output using `indent`, `nindent`, `toString`, `toYaml`, `toJson`, and more: + +```yaml +# Indentation +{{ .Values.multilineConfig | indent 4 }} + +# Type conversion +port: {{ .Values.app.port | toString }} + +# Multi-line values in ConfigMaps +data: + config.yaml: | +{{ .Values.app.config | toYaml | indent 4 }} +``` + +## Conditional Logic + +Go's `text/template` engine allows the use of if/else statements for conditional rendering: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: app-config +data: + {{ 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 }} +``` + +### Comparison Operators + +```yaml +# 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 }} +``` + +## Range, Loops, and Iteration + +Go's `text/template` engine also allows users to iterate over lists and maps: + +```yaml +# 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:** + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: features-config +data: + features.txt: | + Enabled features: +{{ range .Values.app.features }} + - {{ . }} +{{ end }} + + ports.conf: | +{{ range $index, $port := .Values.app.ports }} + listen {{ $port }}; +{{ end }} +``` + +## Go Template Variables + +Assign values to go template variables for reuse within a template (note, : + +:::note +Template vars are a feature from Go's `text/template` engine and are _not_ Zarf's Variables. Template variables are +stored locally within the current template, and variable scope is not shared between Zarf Components or the Package. +::: + +```yaml +{{ $appName := .Values.app.name }} +{{ $namespace := .Values.app.namespace | default "default" }} + +apiVersion: v1 +kind: Service +metadata: + name: {{ $appName }}-service + namespace: {{ $namespace }} +spec: + selector: + app: {{ $appName }} +``` + +## Complex Examples + +For comprehensive examples combining multiple template functions, see the [values-templating example](https://github.com/defenseunicorns/zarf/tree/main/examples/values-templating) 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 + +## Using Helm charts within Zarf: +Helm templating happens inside Helm charts (the standard Helm behavior). Use [Helm value mappings](/ref/package-values/#mapping-to-helm-chart-values) to pass Zarf values into Helm charts so they may be accessed in Helm chart templates. + +## Related Documentation + +- [Templating Best Practices](/best-practices/templating/) - Best practices for templating +- [Package Values](/ref/package-values/) - Defining and using package values +- [Actions](/ref/actions/) - Templating in component actions +- [Deployment Values (Legacy)](/ref/values/) - Legacy templating system +- [Sprig Function Documentation](http://masterminds.github.io/sprig/) - Complete Sprig reference