Variables & Templating
Declaring variables
Add a vars section to your pipeline:
name: deployvars: registry: "ghcr.io/myorg" env: "staging"steps: - id: push run: "docker push $PIPE_VAR_REGISTRY/app:latest" - id: deploy run: "kubectl apply -n $PIPE_VAR_ENV -f deploy.yaml"Each variable is exposed as PIPE_VAR_<KEY> with hyphens converted to underscores and the name uppercased.
The vars contract
The vars block is the contract for what variables your pipeline accepts. All override sources — .env files, PIPE_VAR_* environment variables, and CLI KEY=value flags — can only override keys that are declared in vars.
If an override source provides a key that is not declared in vars, the key is ignored and a warning is shown:
WARN "SECRET_KEY" from dot_file has no effect — not declared in varsWARN "PIPE_VAR_NONAME" is set but has no effect on this pipelineWARN "custom_flag" passed via CLI has no effect — not declared in varsThis ensures pipelines are explicit about which variables they use. Warnings appear during both pipe run and pipe lint.
Bypassing the contract
Set PIPE_EXPERIMENTAL_UNSAFE_VARS to disable the vars contract. This allows override sources to introduce new keys not declared in vars, and suppresses all related warnings:
PIPE_EXPERIMENTAL_UNSAFE_VARS=1 pipe deploy custom_flag=trueThis is experimental and unsafe — pipelines lose the guarantee that only expected variables are injected.
Loading variables from a .env file
Add a dot_file field to your pipeline to load variables from a standard .env file:
name: deploydot_file: ".env"vars: registry: "ghcr.io/myorg" env: "staging"steps: - id: push run: "docker push $PIPE_VAR_REGISTRY/app:latest"The .env file uses plain NAME=value format (no PIPE_VAR_ prefix needed):
registry=docker.io/myorgenv=productionEach key is matched against the vars block and automatically mapped to PIPE_VAR_<KEY>. Keys not declared in vars are ignored with a warning.
If the .env file is missing, the pipeline continues silently — use a full path or run pipe from the directory containing the file. Malformed lines (e.g., missing =) are skipped with a warning.
Precedence
Variables resolve from four sources with increasing priority:
| Priority | Source | Description |
|---|---|---|
| 1 (lowest) | YAML vars | Default values in the pipeline file |
| 2 | .env file | Values from the dot_file path |
| 3 | System environment | PIPE_VAR_* env vars set before running |
| 4 (highest) | CLI overrides | KEY=value arguments after the pipeline name |
Only keys declared in vars are accepted from any source.
# Uses YAML default for "registry", overrides "env"pipe deploy env=production
# System env overrideexport PIPE_VAR_REGISTRY=docker.io/myorgpipe deployGo template syntax
Variable values support Go text/template syntax, executed against the system environment:
vars: user: "{{ .USER }}" branch: "{{ .GITHUB_REF_NAME | default \"main\" }}" home: "{{ .HOME }}/projects"The default function provides a fallback when the environment variable is unset or empty:
vars: region: "{{ .AWS_REGION | default \"us-east-1\" }}"How it works
- Pipe reads each var value from the YAML.
- If the value contains
{{, it is parsed as a Go template. - The template is executed with the system environment as a flat map (e.g.,
.HOME,.USER,.PATH). - If parsing or execution fails, the original string is used as-is (graceful degradation).