Argo Workflows can use built-in variables within expressions to dynamically inject information into your workflow.
Here’s a simple Argo Workflow that demonstrates using a built-in variable:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: built-in-var-demo-
spec:
entrypoint: main
templates:
- name: main
container:
image: alpine:latest
command: [sh, -c]
args:
- echo "Hello from workflow {{workflow.name}}!"
When this workflow runs, the {{workflow.name}} expression will be replaced with the actual name of the running workflow, which Argo generates automatically (e.g., built-in-var-demo-abc12). The output will look like:
Hello from workflow built-in-var-demo-abc12!
This basic example showcases the power of dynamic injection. Let’s explore the system more deeply.
The Problem Solved: Dynamic Configuration and Context
Workflows often need to adapt based on their execution context. Hardcoding values like environment names, timestamps, or unique identifiers within your workflow definitions leads to brittle configurations. You’d have to manually edit and redeploy for every slight variation. Built-in variables provide a clean, declarative way to inject this contextual information directly into your workflow steps, making them more reusable and adaptable.
How it Works Internally: The Expression Engine
Argo Workflows uses a powerful expression engine that parses and evaluates expressions enclosed in double curly braces, like {{workflow.name}}. This engine understands a specific syntax that allows access to various pieces of information available during workflow execution. These pieces of information are grouped into distinct "namespaces" or "contexts."
The primary contexts you’ll encounter are:
workflow: Information about the current workflow instance.pod: Information about the pod executing the current step.task: Information about the current task (a step within a template).inputs: Values passed into a template or artifact.outputs: Values produced by a template or artifact.steps: Results from previous steps in the workflow.labels: Labels applied to the workflow.annotations: Annotations applied to the workflow.
The syntax {{context.key.subkey}} is used to access nested values. For instance, {{workflow.creationTimestamp}} accesses the timestamp when the workflow was created.
Key Built-In Variables and Their Uses
Here’s a breakdown of some commonly used built-in variables and how they are useful:
-
{{workflow.name}}: The name of the current workflow instance. Useful for logging, creating unique resource names, or identifying specific runs. -
{{workflow.uid}}: A unique identifier for the current workflow instance. Excellent for ensuring idempotency or for cross-referencing with other systems. -
{{workflow.creationTimestamp}}: The timestamp when the workflow was created. Can be used for time-based logic or to tag outputs with creation time. -
{{pod.name}}: The name of the pod currently executing the step. Essential for debugging or when a step needs to refer to its own pod. -
{{pod.namespace}}: The Kubernetes namespace where the workflow is running. Useful for deployments that need to be aware of their environment. -
{{task.name}}: The name of the current task (step). Helps in identifying which part of the workflow is producing output or encountering an error. -
{{inputs.parameters.param-name}}: Accesses input parameters passed to a template. This is fundamental for parameterizing your workflows. -
{{steps.step-name.outputs.result}}: Retrieves the outputresultfrom a previous step namedstep-name. This is how you chain data between steps. -
{{workflow.labels.label-key}}: Accesses a specific label applied to the workflow.
Let’s see {{steps.step-name.outputs.result}} in action:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: step-output-demo-
spec:
entrypoint: main
templates:
- name: main
steps:
- - name: produce-value
template: producer
- - name: consume-value
template: consumer
dependencies: [produce-value]
- name: producer
container:
image: alpine:latest
command: [sh, -c]
args: ["echo 'some_data' > /outputs/data.txt"]
outputs:
artifacts:
- name: output-data
path: /outputs/data.txt
- name: consumer
container:
image: alpine:latest
command: [sh, -c]
args:
- echo "The value from the previous step is: {{steps.produce-value.outputs.artifacts.output-data.path}}"
In this example, the producer template writes data to a file, which is then captured as an artifact. The consumer template, which depends on producer, accesses the path to that artifact using {{steps.produce-value.outputs.artifacts.output-data.path}}. Argo automatically makes the content of this artifact available to the consumer, and the expression engine resolves the path.
The "One Thing" Most People Don’t Know
While it’s common to see {{workflow.name}} or {{inputs.parameters.myparam}}, many users overlook the {{tasks}} context, which provides access to detailed information about the execution of a specific task (step). For example, {{tasks.mytask.outputs.parameters.myparam}} can retrieve a parameter output from a task named mytask, even if that task is part of a different template or a parallel branch. This is incredibly useful for consolidating results or making decisions based on the outcome of specific, named tasks within a complex workflow graph. You can also inspect {{tasks.mytask.status}} to check if a task succeeded, failed, or is pending.
The next hurdle for many is understanding how to use these variables in more complex scenarios, such as dynamically generating Kubernetes resource manifests or orchestrating complex conditional logic based on runtime values.