OrchStep uses Go templates with Sprig functions for variable interpolation, and supports JavaScript expressions via the Goja VM for complex logic.
Expressions are enclosed in {{ }}:
do: echo "Deploying {{ vars.version }} to {{ vars.environment }}"
| Pattern | Description |
|---|
{{ vars.name }} | Workflow variable |
{{ steps.step_name.field }} | Step output |
{{ env.VAR_NAME }} | Environment variable |
{{ result.output }} | Current step result (in outputs:) |
{{ loop.item }} | Current loop item |
{{ loop.index }} | Current loop index (zero-based) |
echo "Deploying to {{ vars.env }}"
{{- if eq vars.env "production" }}
echo "Extra production checks enabled"
OrchStep includes Sprig v3 with 100+ utility functions.
| Function | Example | Result |
|---|
upper | {{ "hello" | upper }} | HELLO |
lower | {{ "HELLO" | lower }} | hello |
title | {{ "hello world" | title }} | Hello World |
trim | {{ " hello " | trim }} | hello |
trimSuffix | {{ "hello.txt" | trimSuffix ".txt" }} | hello |
replace | {{ "hello" | replace "l" "r" }} | herro |
contains | {{ contains "hello" "ell" }} | true |
hasPrefix | {{ hasPrefix "hello" "hel" }} | true |
hasSuffix | {{ hasSuffix "hello" "llo" }} | true |
repeat | {{ "ab" | repeat 3 }} | ababab |
substr | {{ substr 0 5 "hello world" }} | hello |
trunc | {{ trunc 5 "hello world" }} | hello |
camelcase | {{ "my-service" | camelcase }} | myService |
snakecase | {{ "myService" | snakecase }} | my_service |
kebabcase | {{ "myService" | kebabcase }} | my-service |
split | {{ split "," "a,b,c" }} | list [a, b, c] |
join | {{ list "a" "b" "c" | join "," }} | a,b,c |
| Function | Example | Result |
|---|
add | {{ add 1 2 }} | 3 |
sub | {{ sub 10 3 }} | 7 |
mul | {{ mul 3 4 }} | 12 |
div | {{ div 10 3 }} | 3 |
mod | {{ mod 10 3 }} | 1 |
max | {{ max 5 10 }} | 10 |
min | {{ min 5 10 }} | 5 |
ceil | {{ ceil 1.5 }} | 2 |
floor | {{ floor 1.5 }} | 1 |
| Function | Description |
|---|
first | First element of a list |
last | Last element of a list |
rest | All elements except first |
append | Add element to end of list |
concat | Merge two lists |
uniq | Remove duplicate elements |
has | Check if list contains element |
without | Remove elements from list |
slice | Sub-list extraction |
reverse | Reverse list order |
| Function | Description |
|---|
get | Get value by key |
set | Set value for key |
hasKey | Check if key exists |
keys | Get all keys |
values | Get all values |
pick | Select subset of keys |
omit | Exclude subset of keys |
merge | Merge dictionaries |
| Function | Description |
|---|
atoi | String to integer |
toString | Convert to string |
toJson | Serialize to JSON string |
toPrettyJson | Serialize to formatted JSON |
fromJson | Parse JSON string to object |
toYaml | Serialize to YAML string |
| Function | Example |
|---|
now | Current time |
date | {{ now | date "2006-01-02" }} |
dateModify | {{ now | dateModify "+24h" }} |
unixEpoch | {{ now | unixEpoch }} |
| Function | Description |
|---|
b64enc | Base64 encode |
b64dec | Base64 decode |
sha256sum | SHA-256 hash |
urlquery | URL-encode string |
uuidv4 | Generate UUID v4 |
| Function | Example |
|---|
default | {{ vars.port | default 8080 }} |
empty | {{ empty vars.name }} |
coalesce | {{ coalesce vars.a vars.b "fallback" }} |
ternary | {{ ternary "yes" "no" (eq vars.env "prod") }} |
| Function | Description | Example |
|---|
regexMatch | Test if string matches pattern | {{ regexMatch "v[0-9]+" vars.version }} |
regexFind | Extract first capture group | {{ result.output | regexFind "ID=(.+)" }} |
regexFindAll | Extract all matches | {{ regexFindAll "[0-9]+" result.output -1 }} |
regexReplaceAll | Replace all matches | {{ regexReplaceAll "[0-9]+" result.output "X" }} |
| Function | Example |
|---|
semver | {{ semver "1.2.3" }} — parse to semver object |
semverCompare | {{ semverCompare ">=1.2.0" vars.version }} — compare versions |
Use regex in outputs: to extract structured data from command output:
echo "IMAGE=myapp:v1.2.3"
echo "DIGEST=sha256:abc123"
image: '{{ result.output | regexFind "IMAGE=(.+)" }}'
digest: '{{ result.output | regexFind "DIGEST=(.+)" }}'
size: '{{ result.output | regexFind "SIZE=(.+)" }}'
output_field: '{{ result.output | regexFind "KEY=(.+)" }}'
# Extract JSON field from mixed output
json_field: '{{ result.data.field_name }}'
# Trim whitespace from output
clean_output: '{{ result.output | trim }}'
safe_value: '{{ result.output | default "unknown" }}'
version: '{{ result.output | regexFind "([0-9]+\\.[0-9]+\\.[0-9]+)" }}'
For complex logic that goes beyond Go templates, OrchStep supports JavaScript via the Goja VM. JavaScript is used in:
assert conditions (when no {{ }} wrapper)
retry.when conditions
loop.until conditions
transform function do: blocks
condition: 'steps.api.status_code >= 200 && steps.api.status_code < 300'
# Retry with JavaScript condition
!result.output.includes('invalid') &&
# Loop until with JavaScript
until: 'steps.check.output.includes("READY")'
- Use single quotes around Go template conditions to avoid YAML escaping:
'{{ eq vars.x "y" }}'
- Prefer
regexFind over complex shell parsing for output extraction
- Use
default to provide fallback values: {{ vars.port | default 8080 }}
- Use
trim on extracted outputs to remove trailing newlines
- Use JavaScript syntax for complex boolean logic (more readable than nested Go template
and/or)