# Expressions and data | Docs - nodulz

Source: https://nodulz.com/docs/expressions

Language: en

An expression reads data from the current execution. Run the source first, inspect its output, then select a field through editor mapping. The path depends on the trigger and node options.

## Trigger input

`input` refers to the workflow’s original input. Adding a node does not replace that input with the previous node’s output.

> [!FLOW] Transforming data does not replace the input
>
> 1. **Original input** <!-- node: data -->
>    `input.amount = 120`
> 2. **Edit fields** <!-- node: set -->
>    Adds `5` to the `amount` field.
> 3. **Two available values** <!-- node: data -->
>    `input.amount = 120`\
>    `nodes.set1.amount=125`

To reproduce this diagram, enable **Mapped fields only** in an Edit fields node, create `amount` with value `{{ input.amount + 5 }}`, then inspect its output. Adapt `set1` to the technical name offered by your mapping.

With this payload in a manual trigger:

```json
{
  "email": "ada@example.test",
  "amount": 120,
  "tags": ["demo", "priority"]
}
```

- `{{ input.email }}` reads the address.
- `{{ input.amount }}` reads the number `120`.
- `{{ input.tags[0] }}` reads `demo`.

For a webhook receiving the same JSON as its request body, these paths become `input.body.email`, `input.body.amount` and `input.body.tags[0]`. Headers and URL parameters are available through `input.headers` and `input.query`.

## Node output

`nodes` contains outputs from nodes that have already run, indexed by their technical names. If an HTTP node named `http1` returns:

```json
{
  "body": { "id": "customer-42", "active": true },
  "status": 200,
  "ok": true
}
```

Read the identifier with `{{ nodes.http1.body.id }}`. If you enable **Body only**, the output becomes `{ "id": "customer-42", "active": true }` directly: use `{{ nodes.http1.id }}` instead.

The visible service name is not enough to infer the path. Use the technical name offered by mapping. A node on the other branch of an IF may not have run and therefore supplies no output for this execution.

## Text or typed value

In [Edit fields](/docs/nodes/set), a standalone expression preserves the value’s type:

```text
{{ input.amount }}
{{ input.tags }}
{{ input.amount >= 100 }}
```

For the previous payload, these expressions produce a number, a list and a boolean respectively. In contrast, `Amount: {{ input.amount }}` produces the text `Amount: 120`. Entering just `120` in a value in this form also produces text; `{{ 120 }}` produces a number.

This rule depends on the destination parameter. The HTTP node’s body is text sent over the network. To send an object as JSON, use `{{ JSON.stringify(input) }}` and the header `Content-Type: application/json`. See the [HTTP example](/docs/nodes/http) for configuration.

## Variables created by Edit fields

A simple field named `customerId` can be read as `{{ vars.customerId }}` or `{{ customerId }}`. These variables are stored as text. To preserve a number, object or list downstream, prefer the node’s typed output: `{{ nodes.set1.amount }}` or `{{ nodes.set1.tags }}`.

A dotted name such as `customer.email` builds a nested object in the output. It does not create a global variable named `customer.email`.

## Objects, lists and files

- **JSON object**: read its properties directly. If `nodes.http1.body` is already an object, no conversion is needed to access `nodes.http1.body.id`.
- **String containing JSON**: use [Parse JSON](/docs/nodes/parse_json), for example with the field `input.raw`. The decoded value is available in `nodes.parse1.parsed` if the technical name is `parse1`.
- **List**: to select items and process them one by one, follow [Process a list](/docs/working-with-lists). The guide distinguishes the list path (`source`), the field within each item and the current loop item.
- **File**: check the encoding and metadata expected by the destination. Base64 content, a URL and a file path are not interchangeable.

## Missing values

A missing path can produce `null` in a typed value and empty text when inserted into a string. An empty output therefore does not prove the data was supplied.

For optional text, you can write:

```text
{{ input.name ?? 'Visitor' }}
```

`??` replaces a missing or `null` value but preserves `0`, `false` and an empty string. For a required address or identifier, add a validation condition and a rejection branch instead of inventing a default value.

If the result is unexpected, check the [actual input and executed branch](/docs/troubleshooting#an-expression-is-empty-or-null). Evaluation errors may also leave a diagnostic in the logs.

## Explore further

- [Features - nodulz](https://nodulz.com/product/overview)
- [Node catalog - nodulz](https://nodulz.com/product/catalog)
- [MCP server - nodulz](https://nodulz.com/product/mcp)
- [Pricing - nodulz](https://nodulz.com/pricing)
- [Use cases and workflow automation - nodulz](https://nodulz.com/use-cases)
- [Choose what your workflows can do. - nodulz](https://nodulz.com/compare)
- [Documentation - nodulz](https://nodulz.com/docs)
