Docs / Strand / templating/nested-workflows
Nested Workflows
Call workflows from other workflows to create modular, reusable designs.
Flow Call Node
The Flow Call node executes another workflow as a step in your current workflow.
Configuration
flow_id (required)
- The ID of the workflow to call
- Can be static:
"process-user" - Can be dynamic using templating:
"{{ payload.workflow_to_call }}"
data (optional)
- Custom data to pass to the called workflow
- If not provided, passes current event automatically
- Supports full Jinja2 templating
Example Configuration
Direct connection:
{
"flow_id": "process-user",
"data": {
"user_id": "{{ payload.id }}",
"context": {
"source_workflow": "{{ meta.workflow_id }}",
"timestamp": "{{ meta.received_at }}"
}
}
}
Non-direct access:
{
"flow_id": "process-user",
"data": {
"user_id": "{{ steps.user_lookup.output_payload.id }}",
"context": {
"source_workflow": "{{ meta.workflow_id }}",
"timestamp": "{{ meta.received_at }}"
}
}
}
Passing Data
Default Behavior
If you don't specify data, the current event is passed:
{
"payload": { /* current payload */ },
"meta": { /* current meta */ }
}
Custom Data
Pass a custom object with templating:
Direct connection:
{
"user_id": "{{ payload.id }}",
"processed_data": {{ payload | tojson }}
}
Non-direct access:
{
"user_id": "{{ steps.user_lookup.output_payload.id }}",
"processed_data": {{ steps.process.output_payload | tojson }}
}
Accessing Output
The nested workflow's output is available through the Flow Call node:
{{ steps.flow_call_node.output_payload }}
{{ steps.flow_call_node.output_payload.result }}
Infinite Loop Prevention
Strand automatically prevents infinite loops by tracking the call chain.
How It Works
- System tracks which workflows are in the current call chain
- Before executing a nested workflow, checks if it's already in the chain
- If detected, raises an error with the full call chain
Error Example
Infinite loop detected: workflow 'workflow-a' is calling itself
(directly or indirectly).
Call chain: workflow-a -> workflow-b -> workflow-a
Best Practices
Design hierarchy
Plan workflow dependencies before building
Single responsibility
Each workflow should do one thing well
Document dependencies
Note which workflows call which others
Test incrementally
Test nested workflows individually
Use Cases
Modular Processing
Break complex workflows into smaller pieces:
validate-input- Validates dataprocess-data- Processes validated datasend-notification- Sends notifications
Reusable Components
Create reusable workflow components:
- Authentication workflows
- Data transformation workflows
- Notification workflows
Conditional Execution
Call different workflows based on conditions:
{% if payload.type == 'user' %}
process-user-workflow
{% else %}
process-admin-workflow
{% endif %}
Tendrl