Workflow Helper Functions
For the complete documentation index, see llms.txt. For a full content snapshot, see llms-full.txt. Append.mdto anykestra.io/docs/*URL for plain Markdown.
This group is more situational, but it becomes valuable in complex flows where you need to inspect sibling results, build links back into Kestra, or summarize failures.
loopOutputs()
Extracts a named output from every iteration of a Loop task and returns the values as an ordered list.
Prerequisite: the Loop task must declare an outputs: block. Without it, outputs.loop.outputs does not exist and this function will fail.
{{ loopOutputs(outputs.myLoop.outputs, 'result') }}The first argument must be the loop task’s .outputs list. The second argument is the output ID — it must match an output ID declared in the Loop task’s outputs: block. The function returns one value per iteration in order, with null for iterations where that key is missing.
For a Loop over ["a", "b", "c"] with a declared output result:
{{ loopOutputs(outputs.loop.outputs, 'result') }}{# → ["processed a", "processed b", "processed c"] #}To access a single iteration directly, use list index notation:
{{ outputs.loop.outputs[0].outputs.result }} {# first iteration's declared output #}{{ outputs.loop.outputs[0].item.value }} {# first iteration's input value #}{{ outputs.loop.outputs[0].item.iteration }} {# first iteration's zero-based index #}errorLogs()
Prints all error logs from the current execution:
{{ errorLogs() }}It is most useful in errors blocks, where you need a compact summary of what failed without manually traversing task state objects.
tasksWithState()
Returns a list of task run objects matching the given state. Use it in error handlers or notifications to report which tasks failed:
{{ tasksWithState('FAILED') }}Useful for building conditional logic or failure summaries based on task outcomes.
subflow()
Synchronously runs a subflow and returns its terminal execution result, so you can read the subflow’s outputs, state, or labels from within an expression.
{{ subflow(namespace='company.team', id='my_subflow', inputs={'key': 'value'}).outputs.my_output }}Arguments:
| Argument | Required | Description |
|---|---|---|
namespace | Yes | Namespace of the subflow to run |
id | Yes | Flow ID of the subflow to run |
inputs | No | Map of inputs to pass to the subflow |
revision | No | Specific revision to run; defaults to latest |
labels | No | Labels to attach to the subflow execution |
timeout | No | ISO 8601 duration; defaults to PT1M, hard cap PT5M |
Return value — an object with four fields:
| Field | Type | Description |
|---|---|---|
.id | string | Execution ID of the subflow run |
.state | string | Terminal state name, e.g. SUCCESS, FAILED |
.outputs.<key> | any | Flow-level outputs declared in the subflow’s outputs: block |
.labels.<key> | string | Execution labels as a key → value map |
Primary use case — populating a SELECT or MULTISELECT input’s expression: at form render time:
inputs: - id: datacenter type: SELECT expression: "{{ subflow(namespace='company.ops', id='fetch_datacenters').outputs.datacenter_list }}"When a user opens the Execute form, Kestra runs the subflow synchronously, reads its output, and populates the dropdown before the main flow begins.
Important constraints:
- Only valid in an input
expression:context. Usingsubflow()inside a task or trigger property throws an error, because blocking a worker thread while waiting for a child execution can deadlock a worker under load. - Flows referenced by
subflow()in aSELECTorMULTISELECTinput expression appear in the parent flow’s Dependencies graph, the same way aSubflowtask reference does. - Only available on
WEBSERVERandSTANDALONEserver types. The function is not registered on other server types. - The default timeout is
PT1M. The hard cap isPT5M— passing a largertimeoutvalue is rejected at runtime. Both limits are configurable; see configuration reference. - Subflow recursion depth is capped at 3. A subflow whose own inputs call
subflow()counts against this limit. - Executions triggered by
subflow()carry asystem.from: subflowlabel automatically.
appLink()
Enterprise Edition’s appLink() builds links back to Kestra Apps:
{{ appLink(appId='com.example.my-app') }}{{ appLink(baseUrl=true) }}Use it in notifications when you want recipients to jump directly into the related app rather than the generic flow UI.
Was this page helpful?