Skip to content

Variables Examples


Dynamic Variables with Step Outputs

# Example: Dynamic Variables with Step Outputs
# Steps can produce outputs that subsequent steps consume.
# This creates a data pipeline where each step builds on previous results.
#
# Key concepts:
# - "outputs:" captures values from a step
# - "{{ steps.<step_name>.<output_key> }}" references them later
# - Outputs can combine step results with variables
#
# Try: orchstep run
name: dynamic-variables-demo
desc: "Pass data between steps using outputs"
defaults:
registry_host: "registry.example.com"
namespace: "production"
app_name: "web-api"
tasks:
main:
desc: "Docker build and deploy pipeline showing dynamic variables"
steps:
- name: build_image
desc: "Build the Docker image and capture metadata"
func: shell
do: |
echo "Building Docker image..."
echo "Image: {{ vars.app_name }}:v2.1.0"
echo "Build complete."
outputs:
image_tag: "v2.1.0"
image_name: "{{ vars.app_name }}"
full_image: "{{ vars.app_name }}:v2.1.0"
- name: tag_for_registry
desc: "Tag the image for the remote registry"
func: shell
do: |
echo "Tagging {{ steps.build_image.full_image }}"
echo " as {{ vars.registry_host }}/{{ steps.build_image.full_image }}"
outputs:
tagged_image: "{{ vars.registry_host }}/{{ steps.build_image.image_name }}:{{ steps.build_image.image_tag }}"
- name: push_image
desc: "Push the tagged image to the registry"
func: shell
do: echo "Pushing {{ steps.tag_for_registry.tagged_image }}"
outputs:
registry_uri: "{{ steps.tag_for_registry.tagged_image }}"
push_status: "completed"
- name: deploy
desc: "Deploy the pushed image to Kubernetes"
func: shell
do: |
echo "kubectl set image deployment/{{ vars.app_name }} \
{{ vars.app_name }}={{ steps.push_image.registry_uri }} \
-n {{ vars.namespace }}"
outputs:
deployed_image: "{{ steps.push_image.registry_uri }}"
- name: summary
desc: "Show the full pipeline result"
func: shell
do: |
echo "=== Deployment Summary ==="
echo "Image: {{ steps.build_image.full_image }}"
echo "Registry: {{ steps.push_image.registry_uri }}"
echo "Status: {{ steps.push_image.push_status }}"
echo "Deployed: {{ steps.deploy.deployed_image }}"

Structured Data with map_in / map_out

# Example: Structured Data with map_in / map_out
# For complex data transformations, OrchStep provides JavaScript-powered
# "map_in" and "map_out" blocks that run before and after a step.
#
# Key concepts:
# - map_in: JavaScript that sets spec.* variables BEFORE the step runs
# (available as {{ vars.* }} inside "do:")
# - map_out: JavaScript that reads result.output AFTER the step runs
# and sets spec.* variables (available in "outputs:")
# - Transient scope: map_in/map_out vars only live during that step
# - "utils" helpers: parseJSON, toJSON, toYAML, upper, unique, sum, etc.
#
# Try: orchstep run
name: structured-data-demo
desc: "Transform data with map_in and map_out (JavaScript)"
tasks:
main:
desc: "Data transformation pipeline"
steps:
# map_in: inject computed variables before shell execution
- name: build_greeting
desc: "Use map_in to prepare variables"
func: shell
map_in: |
spec.greeting = "Hello";
spec.name = "OrchStep User";
do: echo '{{ vars.greeting }}, {{ vars.name }}!'
outputs:
message: "{{ result.output }}"
# map_out: parse and transform command output
- name: parse_status
desc: "Use map_out to parse structured output"
func: shell
do: echo 'status=success,count=42'
map_out: |
const output = result.output.trim();
const parts = output.split(',');
spec.status = parts[0].split('=')[1];
spec.count = parseInt(parts[1].split('=')[1]);
outputs:
status: "{{ vars.status }}"
count: "{{ vars.count }}"
# Both map_in and map_out on the same step
- name: transform_user_id
desc: "Use both map_in and map_out together"
func: shell
map_in: |
spec.prefix = "USR";
spec.id = "00042";
do: echo '{{ vars.prefix }}-{{ vars.id }}'
map_out: |
spec.user_id = result.output.trim();
spec.is_valid = result.output.includes("USR-");
outputs:
user_id: "{{ vars.user_id }}"
valid: "{{ vars.is_valid }}"
# Parse JSON output with the utils helper
- name: parse_json_output
desc: "Use utils.parseJSON in map_out"
func: shell
do: |
echo '{"status":"ok","items":[1,2,3,4,5]}'
map_out: |
const data = utils.parseJSON(result.output);
spec.api_status = data.status;
spec.item_count = data.items.length.toString();
spec.item_total = utils.sum(data.items).toString();
outputs:
api_status: "{{ vars.api_status }}"
item_count: "{{ vars.item_count }}"
item_total: "{{ vars.item_total }}"
- name: summary
func: shell
do: |
echo "=== Structured Data Results ==="
echo "Greeting: {{ steps.build_greeting.message }}"
echo "Status: {{ steps.parse_status.status }}"
echo "Count: {{ steps.parse_status.count }}"
echo "User ID: {{ steps.transform_user_id.user_id }}"
echo "Valid: {{ steps.transform_user_id.valid }}"
echo "API Status: {{ steps.parse_json_output.api_status }}"
echo "Items: {{ steps.parse_json_output.item_count }} (total: {{ steps.parse_json_output.item_total }})"

Variable Precedence

# Example: Variable Precedence
# Full demonstration of how OrchStep resolves variables when the same
# name is defined at multiple levels. Higher levels always win:
#
# Runtime (--var) > Step vars > Task vars > Definition vars
#
# This example uses multiple tasks to show each layer in isolation.
#
# Try: orchstep run
# Try: orchstep run test_step_override
# Try: orchstep run --var multi_level="from-runtime"
name: variable-precedence-demo
desc: "Shows how variables at different levels override each other"
# Definition variables (lowest priority in-file)
defaults:
environment: "global-default"
region: "us-east-1"
replicas: "1"
multi_level: "from-definition"
app_name: "my-app"
tasks:
# Shows definition-level vars when no overrides exist
show_definition_vars:
desc: "Display definition-level defaults"
steps:
- name: show_globals
func: shell
do: |
echo "environment = {{ vars.environment }}"
echo "region = {{ vars.region }}"
echo "replicas = {{ vars.replicas }}"
# Task vars override definition vars
show_task_override:
desc: "Task vars override definition vars"
vars:
environment: "task-staging"
replicas: "3"
task_only: "only-visible-in-this-task"
steps:
- name: show_task_vars
func: shell
do: |
echo "environment = {{ vars.environment }}"
echo "replicas = {{ vars.replicas }}"
echo "region = {{ vars.region }}"
echo "task_only = {{ vars.task_only }}"
# Step vars override task vars (and definition vars)
show_step_override:
desc: "Step vars override task vars"
vars:
environment: "task-qa"
replicas: "5"
steps:
- name: step_with_overrides
desc: "This step overrides environment and replicas"
vars:
environment: "step-production"
replicas: "10"
func: shell
do: |
echo "=== Inside step with overrides ==="
echo "environment = {{ vars.environment }}"
echo "replicas = {{ vars.replicas }}"
- name: step_without_overrides
desc: "This step inherits from the task level"
func: shell
do: |
echo "=== Inside step without overrides ==="
echo "environment = {{ vars.environment }}"
echo "replicas = {{ vars.replicas }}"
# Template expressions in variable values
show_template_vars:
desc: "Variables can use template expressions"
vars:
base_url: "https://api.example.com"
api_version: "v2"
steps:
- name: computed_variable
desc: "Build a URL from other variables"
vars:
full_url: "{{ vars.base_url }}/{{ vars.api_version }}/users"
func: shell
do: |
echo "Base URL: {{ vars.base_url }}"
echo "API Version: {{ vars.api_version }}"
echo "Full URL: {{ vars.full_url }}"
# Main orchestrator runs all demos
main:
desc: "Run all precedence demonstrations"
steps:
- name: demo_definition
task: show_definition_vars
- name: demo_task
task: show_task_override
- name: demo_step
task: show_step_override
- name: demo_template
task: show_template_vars
- name: summary
func: shell
do: |
echo "=== Variable Precedence (highest to lowest) ==="
echo " 1. Runtime (--var key=value)"
echo " 2. Step vars"
echo " 3. Task vars"
echo " 4. Definition vars (defaults:)"

Variable Scoping

# Example: Variable Scoping
# OrchStep resolves variables through a 3-level hierarchy:
# 1. Step vars -- highest priority (most specific)
# 2. Task vars -- mid priority
# 3. Definition vars (defaults:) -- lowest priority
#
# A 4th level -- runtime vars via --var -- overrides everything.
#
# Each level can reference variables from lower levels.
# Step vars are scoped to their step and do not leak to other steps.
#
# Try: orchstep run
# Try: orchstep run --var environment="from-cli"
name: variable-scoping-demo
desc: "Demonstrates the variable scoping hierarchy"
# Level 3: Definition variables (lowest priority)
defaults:
environment: "staging"
app_name: "web-api"
runtime: "nodejs18.x"
tasks:
main:
desc: "Deploy a Lambda function showing variable scoping"
# Level 2: Task variables (override definition vars)
vars:
environment: "production"
memory_size: "512"
steps:
# Level 1: Step variables (override task and definition vars)
- name: package_function
desc: "Package the Lambda function code"
vars:
zip_file: "{{ vars.app_name }}-{{ vars.environment }}.zip"
func: shell
do: |
echo "Creating package: {{ vars.zip_file }}"
echo "Environment: {{ vars.environment }}"
echo "Runtime: {{ vars.runtime }}"
echo "Memory: {{ vars.memory_size }}"
outputs:
package_path: "{{ vars.zip_file }}"
# This step does NOT see the zip_file var from the step above.
# Step vars are scoped -- they don't leak between steps.
- name: create_lambda
desc: "Create the Lambda function"
func: shell
do: |
echo "Creating function: {{ vars.app_name }}"
echo "Package: {{ steps.package_function.package_path }}"
echo "Runtime: {{ vars.runtime }}"
echo "Memory: {{ vars.memory_size }}MB"
# Step vars can also override task vars
- name: configure_trigger
desc: "Configure API Gateway trigger"
vars:
api_name: "{{ vars.app_name }}-api"
stage: "{{ vars.environment }}"
func: shell
do: |
echo "API Name: {{ vars.api_name }}"
echo "Stage: {{ vars.stage }}"

Passing Variables Between Tasks

# Example: Passing Variables Between Tasks
# Tasks can be called from steps using "task:" and receive parameters
# via "with:". This enables reusable task definitions with configurable inputs.
#
# Key concepts:
# - "task:" calls a named task
# - "with:" passes variables to the called task (overrides its defaults)
# - Called tasks define defaults in their own "vars:" section
# - The caller's "with:" values take precedence over the task's defaults
#
# Try: orchstep run
name: vars-between-tasks-demo
desc: "Reusable tasks with parameterized inputs"
defaults:
organization: "acme-corp"
tasks:
# A reusable deployment task with sensible defaults
deploy_service:
desc: "Deploy a service (reusable task)"
vars:
service_name: "unnamed-service"
environment: "dev"
replicas: "1"
steps:
- name: show_config
func: shell
do: |
echo "=== Deploying {{ vars.service_name }} ==="
echo "Org: {{ vars.organization }}"
echo "Environment: {{ vars.environment }}"
echo "Replicas: {{ vars.replicas }}"
outputs:
deployment_id: "deploy-{{ vars.service_name }}-{{ vars.environment }}"
deployed_replicas: "{{ vars.replicas }}"
- name: execute
func: shell
do: |
echo "kubectl apply -f {{ vars.service_name }}.yml \
--replicas={{ vars.replicas }}"
# A reusable health check task
health_check:
desc: "Run a health check (reusable task)"
vars:
service_name: "unknown"
endpoint: "localhost:8080"
steps:
- name: check
func: shell
do: echo "curl http://{{ vars.endpoint }}/health"
outputs:
health_status: "healthy"
# Main task: call the reusable tasks with different parameters
main:
desc: "Orchestrate deployments across environments"
steps:
- name: deploy_to_staging
desc: "Deploy auth-service to staging"
task: deploy_service
with:
service_name: "auth-service"
environment: "staging"
replicas: "2"
- name: deploy_to_production
desc: "Deploy auth-service to production"
task: deploy_service
with:
service_name: "auth-service"
environment: "production"
replicas: "5"
- name: deploy_worker
desc: "Deploy worker to production"
task: deploy_service
with:
service_name: "background-worker"
environment: "production"
replicas: "8"
- name: check_auth
desc: "Health check the auth service"
task: health_check
with:
service_name: "auth-service"
endpoint: "auth.example.com:8080"
- name: summary
func: shell
do: |
echo "=== Deployment Summary ==="
echo "Staging: {{ steps.deploy_to_staging.deployment_id }} ({{ steps.deploy_to_staging.deployed_replicas }} replicas)"
echo "Prod: {{ steps.deploy_to_production.deployment_id }} ({{ steps.deploy_to_production.deployed_replicas }} replicas)"
echo "Worker: {{ steps.deploy_worker.deployment_id }} ({{ steps.deploy_worker.deployed_replicas }} replicas)"
echo "Health: {{ steps.check_auth.health_status }}"