# Expression syntax

> JavaScript expression syntax for variables, operators, and conditions in Flow workflows.

Flow expressions are JavaScript. They reference variables with the `$vars` prefix and compute values in configuration fields, Decision and Switch conditions, and Script code.

For how data moves between nodes and the variables model in depth, see [Variables and data flow](variables-and-data-flow.md).

## Variable references

Every value you reference lives under `$vars`:

```javascript
$vars.httpRequest1.output.body      // node output
$vars.orderTotal                    // variable
$vars.manualTrigger1.output.userId  // trigger input
```

- **Node output**: `$vars.<nodeName>.output`. Every node exposes its result under `.output`. The shape of that object depends on the node, so see each node's reference page for its output fields.
- **Variables**: `$vars.<name>`.
- **Trigger inputs**: `$vars.<triggerName>.output.<inputName>`.

For nested properties use dot notation; for array elements use bracket notation:

```javascript
$vars.httpRequest1.output.body.customer.email
$vars.httpRequest1.output.body.items[0].id
```

## Where you write expressions

Flow has two modes, depending on the field:

**Literal (text) fields** — embed an expression in surrounding text with double curly braces. Use this only where prompt or templated text is expected:

```
https://api.example.com/users/{{ $vars.manualTrigger1.output.userId }}
```

**Expression fields** (Decision and Switch conditions, the Update Variable section) and **Script** code — write the expression directly, with no braces:

```javascript
$vars.httpRequest1.output.statusCode === 200
```

## Operators

Standard JavaScript operators are supported:

| Operator | Example | Result |
|---|---|---|
| Equality | `$vars.status === "active"` | `true` or `false` |
| Inequality | `$vars.count !== 0` | `true` or `false` |
| Comparison | `$vars.price > 100` | `true` or `false` |
| Logical AND | `$vars.isVerified && $vars.isActive` | `true` or `false` |
| Logical OR | `$vars.role === "admin" \|\| $vars.role === "owner"` | `true` or `false` |
| Ternary | `$vars.count > 0 ? "has items" : "empty"` | string |

## String operations

```javascript
"Hello, " + $vars.firstName
$vars.message.toUpperCase()
$vars.email.includes("@uipath.com")
```

Template literals combine variables and static text:

```javascript
`Hello ${firstName}, your order #${orderId} has shipped.`
```

## Optional chaining

Use `?.` to safely access properties that may be undefined:

```javascript
$vars.httpRequest1.output.body?.items?.[0]?.id
```

Returns `undefined` instead of raising a runtime error if any intermediate property is null or undefined.

## Nullish coalescing

Use `??` to provide a default value when a value is null or undefined:

```javascript
$vars.userName ?? "Anonymous"
```

## Common errors

| Symptom | Cause | What to do |
|---|---|---|
| An expression resolves to `undefined` | You referenced a node's output before that node runs, or a field that doesn't exist on the output | Reference output only from upstream nodes; check the node's reference page for its actual output fields. Use optional chaining (`?.`) for properties that may be missing. |
| A Decision or Switch condition behaves unexpectedly or fails | The condition isn't a bare boolean expression, for example, it's written as a `return` statement | Write a plain expression that resolves to `true` or `false`, for example `$vars.order1.output.total > 1000`. Do not use `return`. |
| `Cannot find name '$vars'` (or `'$self'`) | The variable isn't in scope at this node, or `$self` is used on a node that produces no output of its own | Reference only variables shown in the variable picker for that node. `$vars` resolves to in-scope variables only; `$self` is available only on nodes that produce output. |
| A value from another node isn't available to reference | Scope is upstream-only — a node can't see downstream nodes, sibling-branch nodes, or nodes inside a loop it has already exited | Restructure so the producing node is upstream of where you reference it, or carry the value through a variable that's in scope. |
| `$vars.<node>.error` isn't available | A node's error output is in scope only when error handling is enabled on it (or its error path is connected) | Enable error handling on the node, or connect its error handle, then reference `$vars.<node>.error`. |
| `{{ }}` shows as literal text, or a text field doesn't resolve | Mode mismatch: `{{ }}` works only in literal (text) fields | Use `{{ $vars.x }}` only in plain-text fields; in expression fields and in Decision and Switch conditions, write `$vars.x` directly with no braces. |

Decision and Switch conditions run as expressions at runtime. A `return` statement is valid only in Script node code.

## Notes

- Expressions are evaluated at runtime, not at design time. Syntax errors surface when the node executes.
- An expression in a configuration field must resolve to the type that field expects — a condition field must resolve to `true` or `false`.
- The `=` and `=js:` prefixes you may see in a `.flow` file are internal serialization formats. You never type them in the editor.
- Type checking is best-effort. References into loosely-typed outputs (objects or arrays typed as `any`) aren't fully validated, so a typo in a nested field name can pass without a warning — double-check nested paths against the node's output.
