Skip to content
Logicbranchstable

Branch on variable

Route to different next steps based on a value the flow already has — for example, the caller's number at flow start, or a result returned by a sub-flow.…

What it does

A pure case dispatcher. Reads a value from somewhere in the run state (vars.x, event.from, event.to, config.x, or a bare key treated as vars.key), compares it against each case's expected value using the selected operator, and jumps to the first case whose nodeId matches. The cases live at config.cases as an array of { path, op, value, nodeId } — the canonical shape shared by every case-supporting node (see invariant I-3). Each case is rendered as its own outgoing edge in the canvas so you can wire targets by drag-and-drop.

When no case matches, the worker falls through to node.on.__next — that's the right-edge out handle on the canvas. Always wire it to a default target; an unmatched branch with no __next edge logs a warning and leaves the flow stranded on the node. For "set a value, then immediately route on it," use the Set / update variable node's built-in cases instead — it does the write and the dispatch in one step. For digit menus, use IVR menu which has the same case shape applied to gathered DTMF.

When to use it

  • Route VIP callers based on their inbound number — "calls from area code 212 go straight to the priority queue"
  • Branch on a value collected by an upstream HTTP request or Integration call — e.g. send paid customers down one path and trial users down another
  • Pick a language path based on vars.preferredLanguage set by a customScript that read the contact record
  • Implement business hours by reading a flag a previous customScript computed (vars.isOpen → "true" or "false") and routing accordingly
  • After a sub-flow returns, branch on whatever the sub-flow stamped into vars (e.g. vars.lookupResult) without writing the value again

Configuration

Route to different next steps based on a value the flow already has — for example, the caller's number at flow start, or a result returned by a sub-flow. For a digit menu, use the IVR menu node's built-in cases. For 'set a value, then route on it', use the Set / update variable node's cases. Only reach for this when neither of those fits.

FieldLabelTypeRequiredDefaultNotes
casesCases (JSON)jsonOptional{}Array of { path, op, value, nodeId }. Supported ops: ==, !=, >, >=, <, <=, contains, startsWith, endsWith, matches (regex).

Outgoing events: __next

Examples

Route VIPs by inbound area code

Inbound calls starting with +1212 (Manhattan) get the VIP path. Anyone else falls through the right-edge out handle to the standard queue.

{
  "id": "vip-check",
  "type": "branch",
  "config": {
    "cases": [
      { "path": "event.from", "op": "startsWith", "value": "+1212", "nodeId": "vip-queue" }
    ]
  },
  "on": { "__next": "standard-queue" }
}

Multi-case dispatch on a stored variable

A previous step wrote vars.tier. Each case targets a different downstream node; the right-edge fallback catches anything not enumerated.

{
  "id": "route-by-tier",
  "type": "branch",
  "config": {
    "cases": [
      { "path": "vars.tier", "op": "==", "value": "gold",   "nodeId": "gold-path" },
      { "path": "vars.tier", "op": "==", "value": "silver", "nodeId": "silver-path" },
      { "path": "vars.tier", "op": "matches", "value": "^(trial|free)$", "nodeId": "trial-path" }
    ]
  },
  "on": { "__next": "default-path" }
}

Gotchas

  • No-match falls through to on.__next, not to the first case. If you forget to wire the right-edge out handle, an unmatched branch logs branch with no matching case and no fallback edge and the flow stalls. Always wire a default. The literal 'end' is a valid fallback when the right answer is "hang up."
  • All comparisons are stringified before the operator runs. Both sides are coerced to strings via String(value) (with null becoming ''); numeric ops then coerce back via Number(). This means vars.x === 0 matches value: "0" but also value: 0, and null is indistinguishable from "". For strict numeric comparisons stash the value as a string and use >, >=, etc.
  • Path supports four prefixes only. event.from, event.to, vars.<dotted>, config.<dotted>, plus a bare key (treated as vars.key). Anything else returns undefined and the comparison silently uses the empty string. Typos like vars.foo.bar.baz on a non-object intermediate also return undefined — the path walker tolerates it instead of throwing.
  • Cases are evaluated in array order; first match wins. If two cases would both match a value, only the first one fires. Order your cases from most-specific to most-general (e.g. exact-match before regex).
  • Invalid regex patterns in the matches op evaluate to non-match. This is defensive — a typo in a pattern (unterminated group, bad escape, etc.) won't hang or crash the flow; the case simply returns false and routing falls through to on.__next. The worker now logs a warn-level entry containing the bad pattern, the node id, and the underlying compile error, so authoring mistakes surface in logs instead of failing silently. Grep worker logs for invalid regex in matches op if a matches case never fires.
  • The legacy varPath field is honored as an alias for path. Generators MUST emit path; saved flows from older versions of the editor may still use varPath and continue to work. Don't mix them in a single case.