Multi-Condition Router
When two branches are not enough. How condition groups, output paths and boolean expressions let one field fan out to as many routes as you need — and which operators actually evaluate.
A Condition asks one question and gives you two answers. That runs out fast. A lead is Hot, Warm or Cold; a ticket is billing, technical or sales; a deal is under 10k, under 100k, or the kind you tell the founder about. Chaining Conditions together works, but three of them nested is already a workflow nobody wants to open again.
The Multi-Condition Router is the node for that. One node, as many output paths as you need, each with its own rule. On the canvas it appears with a coloured handle per path.
Conditions, groups, paths
This node has more moving parts than most, and they only make sense in order. There are three layers, and each one is built out of the layer below it.
- A condition is one test: a field, an operator, a value. Same shape as the Condition node.
- A group bundles conditions together with AND or OR, and gets a name —
group1,group2. - A path is an output handle with a boolean expression over those groups:
group1=true, orgroup1=true AND group2=false.
The reason for the middle layer is the thing worth understanding. Paths do not have to map one-to-one onto groups. Write the tests once, then combine them differently for each route — which is what makes this a router rather than a switch.
| Field | What it holds |
|---|---|
condition_groups | Groups of logical conditions |
output_paths | Rich output path configurations |
default_path | Default fallback path configuration |
execution_mode | How to handle multiple matching paths One of: first_match · all_matches · error_on_all Defaults to first_match. |
condition_groups
- What it holds
- Groups of logical conditions
output_paths
- What it holds
- Rich output path configurations
default_path
- What it holds
- Default fallback path configuration
execution_mode
- What it holds
- How to handle multiple matching paths One of:
first_match · all_matches · error_on_allDefaults tofirst_match.
A worked example
A contact's lead status changes, and the router sends the run down one of three arms. The connector labels are the path names — that is what you type when you create a path, and what the canvas prints.
One field, three destinations
Click the router to see its groups and paths. Each arm leaves from its own handle.
Scroll for all 6 steps →
Two groups do the testing — one for Hot, one for Warm — and three paths consume them. The third path is the catch-all, and its expression is group1=false AND group2=false: everything that matched neither. That is a deliberate choice worth copying, and the next section explains why.
The Default Path, and why the example does not use it
Every router also has a Default Path — a fallback handle that fires when no other path matches. It is the right tool when you want a safety net without describing what falls into it.
An explicit catch-all path is usually better anyway. It appears in the panel with a name someone can read, its expression states what it catches, and you can give it a priority. A Default Path is silent about all three.
If you author workflows through the API rather than the canvas: wiring branches: { default: … } on this node does not reach the Default Path. The compiler treats default as the primary-flow handle and connects it to path1 instead — so your fallback silently becomes a second copy of path 1, and nothing tells you. Verified 2026-08-01. Wire an explicit path id (path3) until that is fixed.
Which operators actually work
Twelve operators evaluate. They cover text, numbers and emptiness:
| Family | Operators |
|---|---|
| Equality | equals · not_equals |
| Numeric | greater_than · less_than · greater_equal · less_equal |
| Text | contains · not_contains · starts_with · ends_with |
| Emptiness | is_empty · is_not_empty |
Equality
- Operators
equals·not_equals
Numeric
- Operators
greater_than·less_than·greater_equal·less_equal
Text
- Operators
contains·not_contains·starts_with·ends_with
Emptiness
- Operators
is_empty·is_not_empty
The dropdown offers ten more that do nothing. Date and time operators — before, after, date_between, within_last_days and their time_* siblings — are declared in this node's schema and are selectable in the panel, but the evaluator has no branch for them and returns false. A path that depends on one never fires, and there is no error. Verified against the node source, 2026-08-01. Do the date test in a condition node upstream — it implements all 27 — and route on the result.
What happens when two paths both match
Nothing stops two expressions being true at once, so the router needs a rule. That is execution_mode, and the default is usually what you want.
| Mode | What runs | Reach for it when |
|---|---|---|
first_match | The highest-priority matching path, and only that one. | The routes are alternatives — a lead is Hot or Warm, not both. |
all_matches | Every matching path, in parallel. | One event should genuinely cause several things. |
best_match | The single highest-priority match. | Rarely — first_match already does this for ordered paths. |
first_match
- What runs
- The highest-priority matching path, and only that one.
- Reach for it when
- The routes are alternatives — a lead is Hot or Warm, not both.
all_matches
- What runs
- Every matching path, in parallel.
- Reach for it when
- One event should genuinely cause several things.
best_match
- What runs
- The single highest-priority match.
- Reach for it when
- Rarely — first_match already does this for ordered paths.
The failure this creates is quiet. Leave the mode on first_match when you meant several arms to fire, and the extra ones simply never run — no error, just work that silently did not happen. If a path stops firing after you add another one above it, check the priorities before anything else.
Watch out: Needs output_paths[] (id/name/priority/condition_expression) + condition_groups[] + a default_path.
Wire edges on the path handles: path1…pathN and `default`. Operators: contains,not_contains,equals,is_empty,is_not_empty,in.
Condition or Router?
| Use | When |
|---|---|
condition | Two outcomes, one test. Also when you need date or time comparison — it has 27 operators and all of them evaluate. |
multi_condition | Three or more outcomes, or several tests combined differently per route. |
condition
- When
- Two outcomes, one test. Also when you need date or time comparison — it has 27 operators and all of them evaluate.
multi_condition
- When
- Three or more outcomes, or several tests combined differently per route.
Reach for the Router when a third branch appears, not before. Two Conditions in a row are easier to read than a router with two paths, and the router's config panel is a lot of surface for a yes/no question.
Try it
- Add a Multi-Condition Router after any node that returns a record.
- Make one group with a single
equalstest, and two paths: one forgroup1=true, one forgroup1=false. - Wire a different node to each handle and run it both ways.
- Now add a third path whose expression is
group1=trueas well, leave the mode onfirst_match, and watch it never fire. Then switch toall_matches.
Next: Loop — for when the answer is not which path, but doing the same thing to every item in a list.
Related lessons
Base rates — what a piece of evidence is actually worth
A face-recognition system that is 99.9% accurate and almost entirely wrong, and a number that sent an innocent woman to prison. Both are the same arithmetic, and it is the arithmetic that decides what any piece of evidence is worth.
ReadConfirmation and survivorship — what you never looked for
Two questions about evidence you did not go looking for. One is a rule you have to discover, and one is a pattern in five famous people — and in both, the thing that would have told you the truth is the thing nobody checks.
ReadLoss aversion, sunk cost and regression — what it costs you
Four questions you answer about yourself rather than about a scenario, and your own answers are the finding. Then the pattern that makes praise look useless and criticism look like it works, whatever you actually do.
Read
