Skip to main content

Logic nodes

Branching and iteration. See Control flow & branching for how branches are walked.


Condition

@wf::logic:condition · ConditionNode

Evaluates field <operator> value and routes to the true or false branch. Only the matched branch runs.

Config

FieldTypeDefaultNotes
fieldtextRequired. The value to test. Usually an expression, e.g. {{ trigger.age }}.
operatorselect==See operators below.
valuetextThe value to compare against. Not shown for the is_* operators.

Operators: ==, ===, !=, >, >=, <, <=, contains, not_contains, starts_with, ends_with, in, not_in, is_null, is_not_null, is_empty, is_not_empty.

Branches: true, false

Output

{ "actual": "<field>", "operator": "==", "expected": "<value>", "result": true, "branch": "true" }

Switch

@wf::logic:switch · SwitchNode

Compares field against a list of cases and routes to the first matching case's branch, or default.

Config

FieldTypeDefaultNotes
fieldtextRequired. Value to switch on, e.g. {{ trigger.status }}.
casesjsonRequired. Array of { "value": ..., "branch": ... } objects.
strictcheckboxfalseUse === instead of == for matching.

Branches: default, plus one per case's branch.

Output

{ "field": "pending", "matched": "pending" }

Not available in the interactive workflow:build CLI (its per-case branch configuration needs the visual builder). Define it in code.


For each

@wf::logic:loop · LoopNode — label "For each"

Iterates an array. Each visit emits the next item on the body branch; after the last item it emits on main. Wire the end of the body back to the loop node to iterate.

Config

FieldTypeNotes
sourcetextRequired. A dot path to an array in context, e.g. nodes.list-orders.result. (A path, not a {{ }} expression.)

Branches: body, main

Output

  • On body: { "index": 0, "item": <element> } — read as {{ nodes.<id>.item }}.
  • On main (after the last item): { "iterations": <n> }.

The loop cursor is stored in per-execution state, so iteration survives a suspend/resume that happens inside the body.

Example

'nodes' => [
['id' => 'orders', 'type' => ModelListNode::type(), 'config' => ['model' => \App\Models\Order::class]],
['id' => 'loop', 'type' => LoopNode::type(), 'config' => ['source' => 'nodes.orders.result']],
['id' => 'ping', 'type' => HttpRequestNode::type(), 'config' => [
'method' => 'post', 'url' => 'https://hooks.example.com/order',
'body' => ['id' => '{{ nodes.loop.item.id }}'],
]],
['id' => 'done', 'type' => LogNode::type(), 'config' => [
'message' => 'Pinged {{ nodes.loop.iterations }} orders',
]],
],
'edges' => [
['from' => 'trigger', 'to' => 'orders', 'branch' => 'main'],
['from' => 'orders', 'to' => 'loop', 'branch' => 'main'],
['from' => 'loop', 'to' => 'ping', 'branch' => 'body'],
['from' => 'ping', 'to' => 'loop', 'branch' => 'main'],
['from' => 'loop', 'to' => 'done', 'branch' => 'main'],
],