Conditional Node
The Conditional node picks exactly one of its outgoing branches based on a runtime condition, activating that branch’s target and marking every other branch target as skipped.
When to use
Section titled “When to use”Use Conditional whenever the path through the workflow depends on runtime data — a count, a score, a classification, a success/error signal. For fixed forks where all branches should run in parallel, use straight-line edges instead.
Put the decision in the Conditional, not in the node before it. A Script node that outputs {"new_items": 3} and a Conditional that branches on new_items ≥ 1 lets a reader see the rule on the canvas. A Script node that decides for itself and outputs {"skip": false} hides the rule inside its source.
Configuration
Section titled “Configuration”| Field | Description |
|---|---|
condition_type | How the condition is evaluated: rules, field, regex or llm. See below. |
condition_rules | For condition_type: rules — an ordered list of { when, label }. |
condition_expression | For every other type — the dot path, pattern or prompt. |
branches | Map from label to target node ID. The label produced by evaluation selects which target activates. |
default_branch (optional) | Target node ID used when evaluation produces no usable label. |
Condition types
Section titled “Condition types”rules(recommended) — structured comparisons, evaluated top to bottom. The condition appears on the canvas, and every field is checked against the incoming edge’s contract when the workflow is saved.field— a single dot path such as.categoryor.meta.route. Its value is turned into text and used as the branch label. This is not an expression language: pipes, comparisons andif/then/elseare not evaluated and are refused when the workflow is saved.regex—status:\s*(?<label>\w+), matched against the incoming data. The named capture grouplabelis used.llm— a classification prompt. The LLM is instructed to output exactly one of the branch labels. Always pair this with adefault_branch.
jq appears in older workflows as the former name of field. It behaves identically — it only ever read dot paths.
Writing rules
Section titled “Writing rules”Each rule is a list of conditions (when) that must all hold, plus the label to take when they do. The first matching rule wins, and a rule with an empty when always matches — that is how you write the final “otherwise”.
condition_type: rulescondition_rules: - when: - { field: .new_items, op: gte, value: 1 } - { field: .locked, op: eq, value: false } label: generate - when: [] label: skipbranches: generate: write-blog skip: endAvailable operators:
| Operator | Meaning | Value |
|---|---|---|
eq / ne | equal / not equal | any scalar |
gt / gte / lt / lte | ordering | a number, or text compared alphabetically (ISO dates sort correctly) |
in | is one of | a list |
contains | a list holds the value, or text holds the substring | a scalar or substring |
exists | the field is present and not null | — |
empty | absent, null, "", [] or {} | — |
There is no or: write a separate rule for each alternative. When a decision needs real computation, compute it in a Script node and branch on the result.
A missing field makes a comparison false rather than failing. Comparing values that cannot be ordered against each other — a number against text, say — fails the node instead of quietly taking the other branch.
Behavior
Section titled “Behavior”- When cascade reaches the Conditional it claims itself as
runningand evaluates the condition against its input data. - The resulting label is looked up in
branchesto find the target node ID; if there is no usable label,default_branchis used. - All outgoing edges other than the chosen one have their targets inserted as
skipped(so downstream joins can see they settled). - The chosen target is activated via the normal registry path (so nested fan-outs/conditionals still get type-specific activation).
- The Conditional settles as
completed, with_chosen_branchand_target_nodein itsoutput_datafor auditability.
If no target resolves at all, the node is marked failed and the reason is recorded in output_data._condition_error, which fails the execution. A reason is also recorded when default_branch rescued the routing, since the workflow did not branch the way its author intended.
Validation rules
Section titled “Validation rules”condition_typeis required.- Either
branches(non-empty) ordefault_branchmust be set. - Every target referenced in
branchesmust be a real node. - For every label in
branches, an outgoing edge to the target must exist on the graph. - Outgoing edges whose
condition_labelis set must match one of thebrancheslabels. default_branch, if set, must reference an existing node.- For
rules: every rule’slabelmust be one of thebranches; operators that need a value must have one;inneeds a list; and no rule may sit after one with an emptywhen, which would make it unreachable. - For
rules, when a single incoming edge carries a contract: everyfieldmust be declared in it, and the operator and value must match the declared type. - For
field: the expression must be a dot path. - For
regex: the pattern must compile.
Example
Section titled “Example”flowchart LR Classify["Skill: classify-ticket"] --> C{{"Conditional"}} C -->|bug| Bug["Skill: bug-triage"] C -->|feature| Feat["Skill: feature-intake"] C -->|other| Other["Skill: fallback"]With condition_type: llm and a prompt “classify as bug, feature, or other”, the LLM’s label picks the branch. Setting default_branch: other protects against unexpected LLM output.