Skip to content

Control Flow

Two forms. A single-step condition, or a multi-step branch with do: and an optional else:.

# Single-step condition
- if: count > 0
$notify:
invoke: email.send
with: { To: "${alert}", Subject: "Data arrived" }
# Multi-step branch
- if: "len(items) > 0"
do:
- log: "Processing ${= len(items)} items"
- $result:
invoke: transform.run
with: { Data: "${items}" }
else:
- log: "Nothing to process"

Conditions are plain expressions — no ${= ... } wrapper. if: count > 0 is correct; if: "${= count > 0}" is not.

Iterate a list or a map. Inner steps are sandboxed by default — they cannot modify the outer payload. Name the loop to collect outputs.

# Side-effect-only loop (sandboxed)
- for-each: $item in "${products.rows}"
do:
- log: "Row ${_index} of ${_count}: ${item.name}"
# Named loop — collects each iteration's output
- $batched:
for-each: $item in "${products.rows}"
do:
- $row:
invoke: transform.run
with: { Data: "${item}" }

Loop variables available inside do::

VariableMeaning
$item (or your chosen name)The current element.
_index1-based position.
_countTotal number of elements.
_keyThe current key (map iteration only).

Two modes: match a value against named cases, or evaluate boolean expressions in order (first match wins).

# Value mode
- switch:
on: "${order.status}"
case:
paid:
- $ship:
invoke: warehouse.create-shipment
cancelled:
- log: "Skipping cancelled order ${order.id}"
default:
- log: "Unhandled status: ${order.status}"
# Expression mode (first match wins)
- switch:
cases:
"len(items) > 1000":
- log: "Large batch — escalating"
"len(items) > 0":
- log: "Small batch"
default:
- log: "Empty batch"
- halt: true # exit the current loop
- halt: { global: true } # terminate the whole flow

Use halt: true to break out of a for-each:; use halt: { global: true } to stop the entire invocation without producing output (contrast with return:, which produces the typed output and ends).