Skip to main content
FlowPilot has three small evaluation systems: conditions (used by dynamic values), property values (static or conditional), and expressions (the {{ }} interpolation and the assign action). Each is deliberately limited. This page documents exactly what is supported so you do not write something the runtime silently drops.

Conditions

A Condition is a pure, read-only test against a variable. It never mutates state and must be deterministic. Conditions read variables only, through a VarRef:
Each operator names a left (a VarRef) and, for most operators, a right literal.

Operators by type

The empty-check operators (is_empty, is_not_empty) take no right operand.

is_full — a list’s selection limit

is_full is true when a List variable has reached the Selection limit (maxSelections) declared on the variable itself. It takes no right operand: the limit is never repeated in the condition, so re-capping a question is a one-number edit on the variable and the conditions can’t drift out of sync with it. A list with no limit is never full, so is_full is inert — always false — until a limit is declared. It is false for every non-list type. This is what greys out the remaining answers of a capped multi-select question. The editor compiles this onto each option automatically when you set a Max selections — you rarely write it by hand:
Both halves matter: without the second, a full question would freeze the user’s own picks and strand them at the limit with no way back. See Limiting how many answers can be picked.

Logical operators

Compose conditions with:

Shape examples

Evaluation notes

  • A type mismatch fails the comparison rather than throwing. A numeric operator on a non-number returns false. A starts_with/ends_with/contains on a non-string returns false (for not_contains, an absent/non-string value returns true).
  • A missing variable is treated as empty: is_empty is true, is_not_empty is false.
  • An unknown operator fails safely to false.
  • The dashboard renderer (variable-runtime.ts) and both SDKs (each ships a ConditionEvaluator, kept in lockstep) implement the same operator set.

Property values

Component props can be a plain value or a PropertyValue<T>:
Resolution rules:
  1. static: return the value directly.
  2. conditional: evaluate cases in order. The first case whose when condition is true wins.
  3. If no case matches, fall back to else.
  4. If nothing matches and there is no else, the result is undefined (the renderer uses its own default).
A ConditionalCase<T> is { when: Condition; value: PropertyValue<T>; label?: string }. Case values can themselves be conditional, so they nest. Example: a color that depends on a variable.

Interpolation: {{ }}

String props support {{variableName}} interpolation. The braces are replaced with the variable’s current value, converted to a string.
  • Only the variable’s value is substituted. The braces hold a bare variable name, nothing else.
  • A missing variable resolves to an empty string.
  • Interpolation re-runs when the variable changes.
{{ }} interpolation does string substitution only. There is no ternary or conditional syntax inside {{ }}. To switch a value based on a condition, use a conditional property value (case/else against a condition) instead.
To switch a value on a condition, use a conditional PropertyValue (shown above), not an expression inside {{ }}.

Expressions (the assign subset)

The assign action and node use a FlowExpression: a string in a small “JS-like” safe subset. The SDKs’ ExpressionEvaluator (the iOS and Expo implementations are kept in lockstep) defines the supported contract: Supported
  • Literals: true, false, null, numbers (decimal, negative, leading dot), and quoted strings ("..." or '...').
  • Variable references: a bare identifier (userName) or a vars. prefix (vars.userName).
  • A single binary arithmetic operator (+, -, *, /, %) when both operands resolve to numbers.
  • String concatenation with + when either operand resolves to a string (the other operand is coerced).
Not supported
  • Parentheses.
  • Comparison operators (>, <, ==, and so on). Use a condition for comparisons.
  • Function calls.
  • Multi-operator chains (for example a + b + c). Only one top-level operator is parsed.
Failure handling An expression that cannot be evaluated returns nothing, and the runtime treats that as “skip this assignment”. The variable is left unchanged. A misconfigured expression never writes an empty, zero, or false value by accident. Division or modulo by zero also skips. Use a condition and a setVariable action when you need comparisons or branching, since expressions cannot compare.

Examples