Skip to content
LogicsetVarstable

Set variable

Save a value to a flow variable so later steps can read it as {{vars.name}}. Add cases below to branch on the value right here — no separate Branch node n…

What it does

Writes a value to a flow variable so later steps can read it as {{vars.<name>}} in templates or via vars.<name> in customScripts. The op field controls how the new value combines with what's already there: set overwrites, append and prepend concatenate strings, increment and decrement do numeric math, toggle flips a boolean, push adds an entry to an array, delete removes the variable entirely, and random / randomInt produce stochastic values for game-style flows. The value field is rendered as a template before the op runs, so {{event.from}}, {{vars.other}}, and {{config.x}} all work.

After the write, this node auto-advances. If you've configured cases on it (the unified { path, op, value, nodeId } shape — see invariant I-3), it dispatches on the just-written value and follows the matching case's edge. When no case matches, it falls through to the first outgoing transition wired in the canvas. This means a single node can do "compute → branch on result" in one step — the dedicated Branch on variable node is only needed when you're routing on a value somebody else already wrote.

When to use it

  • Stash the caller's number at the start of a flow so a later sub-flow can read it without referencing event.from
  • Build a counter for retry logic: op: increment on a vars.attempts variable, then route via cases — "after 3 attempts, give up"
  • Compose a formatted string for a TTS prompt — op: append to glue pieces together as the flow progresses
  • Roll a die for game-show callers (op: randomInt, value: "1,6") and route on the result with cases on the same node
  • Toggle a boolean flag (op: toggle) to flip between two paths on alternating calls — useful for crude round-robin between two destinations without a real queue
  • Clear out a stale value (op: delete) before re-running a sub-flow that reads it as an input

Configuration

Save a value to a flow variable so later steps can read it as {{vars.name}}. Add cases below to branch on the value right here — no separate Branch node needed.

FieldLabelTypeRequiredDefaultNotes
nameVariable nametextRequiredcallerTierReference later as {{vars.callerTier}}.
opOperationselectOptionalsetOptions: set, append, prepend, increment, decrement, toggle, push, delete, random, randomInt. How to combine the new value with the existing variable.
valueValuetextOptionalgoldPlain text or a template. Examples: {{event.from}}, {{vars.gatheredDigits}}. For randomInt, use "min,max" — e.g. "1,6" for a die. For toggle/random/delete this field is ignored.

Examples

Stash a value and continue

The simplest form: write vars.callerTier to gold and follow the single outgoing edge.

{
  "id": "mark-vip",
  "type": "setVar",
  "config": {
    "name": "callerTier",
    "op": "set",
    "value": "gold"
  },
  "on": { "__next": "vip-queue" }
}

Increment a retry counter and branch on the result

After three failed gather attempts, hand off to a human; otherwise loop back to the prompt. The cases are evaluated against the value just written.

{
  "id": "bump-attempts",
  "type": "setVar",
  "config": {
    "name": "attempts",
    "op": "increment",
    "value": "1",
    "cases": [
      { "path": "vars.attempts", "op": ">=", "value": "3", "nodeId": "give-up" }
    ]
  },
  "on": { "__next": "retry-prompt" }
}

Gotchas

  • op: increment and decrement quietly coerce non-numeric values. The current value runs through Number(...) and falls back to 0 when it's NaN. So an increment against an unset or string-shaped variable starts at 0 + step, not at the string. Useful for "first time through" counters; surprising if you were storing "3" and wanted strict typing.
  • op: push parses the rendered value as JSON before pushing. If value parses successfully, the parsed object is pushed; if it doesn't parse, the raw string is pushed instead. Pushing a literal "foo" works; pushing {"id":1} works too — but a string that happens to look like JSON (e.g. a phone number with leading +1) will land as a string because it's not valid JSON.
  • op: delete clears the var; subsequent reads return undefined. Templates render undefined as the empty string, not the literal word "undefined." If something downstream is doing equality on the missing var, it will compare against "".
  • Cases run on the value AFTER the op. The case dispatcher sees the newly-written value, not the previous one. If you need to branch on the old value, do that with a separate branch node before the write.
  • randomInt parses value as "min,max", "min..max", or "min-max". All three separators work. An unparseable value defaults to the range 0..100. The bounds are inclusive on both ends, so "1,6" rolls a fair six-sided die.
  • name is templated through String(...) only, not rendered. The variable name itself does NOT support {{vars.x}} — only the value field does. If you need a dynamically-named variable, use a customScript and write to vars[someKey] directly.