# Expression syntax

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

An expression is a short piece of JavaScript, a widely used programming language, that reads or computes a value. Expressions in a workflow reference values with the `$vars` prefix, and they are used in configuration fields, Decision and Switch conditions, and Script code.

[Variables and data flow](variables-and-data-flow.md) describes how data moves between nodes and how variables work.

## 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 each page of the [node reference](node-reference.md) lists the output fields of its node.
- Variables: `$vars.<name>`.
- Trigger inputs: `$vars.<triggerName>.output.<inputName>`.

Nested properties use dot notation, and array elements use bracket notation:

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

## Where you write expressions

The rule in short: write `$vars…` directly in Script code, in conditions, and in fields set to **Expression**, and wrap it in `{{ $vars… }}` inside text fields set to **Fixed value**.

Most configuration fields can hold either a fixed value or an expression. An icon at the right end of the field opens a menu with three options:

- **Fixed value**: enter a value directly.
- **Expression**: write a JavaScript expression. The editor offers IntelliSense, which suggests names and properties as you type. In this mode the field shows an `=` before the expression.
- **Clear value**: empties the field.

The **Insert** menu next to the field label opens a searchable list of the values that are available at that node. The list is a tree under `$vars`, with one entry for each node, its `output`, and the fields inside it, and each field shows its type, such as `string` or `object`. The list also has a `$metadata` group with the entries `FolderKey`, `InstanceId`, `ProcessKey`, and `ElementCount`.

### Fixed value fields

A field set to **Fixed value** holds text. To embed an expression in the text, select a value from the **Insert** menu, which wraps the reference in double curly braces. The editor checks the reference and reports a problem below the field, for example when a property does not exist on the node's output:

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

### Expression fields and Script code

A field set to **Expression**, Decision and Switch conditions, the **Update Variable** section, and Script code take the expression directly, with no braces:

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

In an expression field, text and a value are combined by joining them with `+` or by using a template literal. Both of the following produce the same result:

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

## 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 ${$vars.firstName}, your order #${$vars.orderId} has shipped.`
```

## Optional chaining

The `?.` operator safely reads properties that may be undefined:

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

The result is `undefined`, instead of a runtime error, if any intermediate property is null or undefined.

## Nullish coalescing

The `??` operator provides 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 is not available to reference | Scope is upstream-only: a node cannot see downstream nodes, nodes in a sibling branch, 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`. |
| `Failed to evaluate expression =js:(https://...)`: `Unexpected token ':'` | A plain value, such as a URL, is in a field set to **Expression** without quotes, so it is read as JavaScript | Switch the field to **Fixed value**, or put the text in quotes, for example `"https://api.example.com/users"`. |
| `{{ }}` shows as literal text, or a text field does not resolve | Mode mismatch: `{{ }}` works only in fields set to **Fixed value** | Use `{{ $vars.x }}` only in fixed-value 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`.
- An expression field shows an `=` before the expression to mark expression mode. The `=js:` prefix that appears in a `.flow` file is an internal serialization format, and you never type it in the editor.
- Type checking is partial. References into outputs without a fixed structure are not fully validated, so a typo in a nested field name can pass without a warning. Compare nested paths with the output fields listed in the node reference.

## Next steps

- [Variables and data flow](variables-and-data-flow.md): how data moves between nodes.
- [Script](node-script.md): write JavaScript in a node.
- [Community](community.md): ask questions and share workflows with other builders on the UiPath Forum.
