> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spojit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Passing Data Between Nodes

> How to reference trigger payloads and previous step outputs in node configuration.

Every node in a workflow can reference data produced by earlier steps. You do this with **template expressions** (double-curly-brace placeholders like `{{ something }}`) anywhere in a node's configuration (prompts, headers, body, connector arguments, etc.).

This page covers:

* The two data sources: the **trigger payload** and **step outputs**
* How to name a step's output so other nodes can reference it
* Type preservation vs string interpolation
* Common pitfalls

***

## The two data sources

There are only two things you can reference from a template expression.

### 1. The trigger payload: `{{ input }}`

Whatever data started the workflow is available under the name `input`. This is:

* The webhook body, for webhook-triggered runs
* The input data you pass to a manual run
* (Soon) the context object for scheduled runs

**Example:** a webhook sends:

```json theme={null}
{
  "customer_id": "cus_123",
  "order": { "total": 99.99, "currency": "USD" }
}
```

Inside any node, you can reference:

* `{{ input.customer_id }}` → `"cus_123"`
* `{{ input.order.total }}` → `99.99`
* `{{ input }}` → the whole object

### 2. Previous step outputs

Any node *upstream* of the current one (connected via the graph) can expose its output to downstream nodes, but only if you give the step an **output variable name** in its properties panel.

If you don't set an output variable, the step's result is still computed but it's stored under a hard-to-use autogenerated name. **Always set an output variable** when a downstream node needs to reference the result.

***

## Setting an output variable

1. Click the node whose output you want to reference
2. Find the **Output Variable** field in its properties panel (all node types that produce output have this)
3. Enter a readable identifier, e.g. `user_lookup`, `agent_result`, `parsed_csv`
4. In a downstream node, reference it: `{{ user_lookup }}`, `{{ agent_result }}`, `{{ user_lookup.id }}`, etc.

<Tip>
  Use snake\_case or camelCase: just letters, digits, and underscores. Avoid spaces, hyphens, and special characters.
</Tip>

***

## What's inside a step output

The shape depends on the node type. The most common ones:

### AI Agent (Connector node in Agent mode)

The bound value is the agent's **primary output**:

* **Without a Response Schema**: `{{ agent_result }}` is the AI's text answer (a string).
* **With a Response Schema**: `{{ agent_result }}` is the structured object the schema defined; address fields directly: `{{ agent_result.userName }}`, `{{ agent_result.items[0].id }}`, etc.

### Connector in Direct mode

`{{ connector_result }}` is the parsed tool payload. For HTTP-style tools that's `{ data, status, headers, statusText }`; drill into the response body with `{{ connector_result.data }}` and the status code with `{{ connector_result.status }}`. For other tools the shape is whatever the tool returned; check the connector's documentation.

### Knowledge: Query mode (RAG)

Same rule as AI Agent: without a Response Schema, `{{ query_result }}` is the synthesised answer string; with a schema it's the structured object.

### Knowledge: Embed mode

`{{ embed_result }}` is `{ chunkCount, collectionName, documentType }`.

### Transform, Condition, Loop, Human Approval, Send Email, etc.

Each node type produces data in the shape documented on its node page. Open the specific node page under **Node Types** for details.

<Tip>
  When you need to reshape data between two steps without an LLM, the
  [Transform](/workflow-editor/nodes/transform) node lets you author the output
  shape using these same `{{ … }}` templates, including `{{ item }}` /
  `{{ index }}` for per-element mapping over an array.
</Tip>

***

## Type preservation

Templates come in two flavors:

### Standalone expression: type preserved

When the **entire value** of a field is a single `{{ ... }}`, the resolver returns the original type without string conversion:

```json theme={null}
{
  "total": "{{ input.order.total }}",
  "items": "{{ input.order.items }}"
}
```

Here `total` resolves to a **number** (`99.99`) and `items` to an **array**, not to strings. This is critical when downstream systems expect typed JSON.

### Mixed with text: coerced to string

When templates are mixed with literal text, everything becomes a string:

```
Hi {{ input.customer.name }}, your order total is {{ input.order.total }}.
```

Resolves to `"Hi Alice, your order total is 99.99."` Numbers and objects get serialized to JSON inline.

***

## Example: chaining nodes

A workflow that receives a webhook, asks an AI agent to process the payload, then returns an HTTP response:

```
Webhook  →  AI Agent (outputVariable: joke)  →  Response
```

**Webhook payload:**

```json theme={null}
{ "topic": "programming" }
```

**AI Agent node** Prompt:

```
Write a short joke about {{ input.topic }}.
```

**AI Agent node** Output Variable: `joke`

**Response node** Body:

```json theme={null}
{
  "status": "ok",
  "topic": "{{ input.topic }}",
  "joke_text": "{{ joke }}"
}
```

When the webhook fires, the response returns the AI-generated joke with the trigger topic preserved.

***

## Common pitfalls

### Referencing a step before setting its output variable

`{{ joke }}` returns `null` (and renders as the literal string `"null"` in mixed contexts) if no upstream node has output variable `joke`. Check the output variable is set on the correct node.

### Forgetting to save and re-compile

Edits to node configuration are saved to the **canvas**; the compiled version of the workflow graph (what webhooks actually run) is regenerated when the workflow compiles. This happens automatically on **Save** and when you click **Run**. If you edit directly via API and skip compile, webhooks will keep running the old compiled version.

### Using `{{ result }}` without specifying which step

`result` is not a reserved name. If no node has `outputVariable: result`, this resolves to `null`. Always name your variables per-step (`{{ agent_result }}`, `{{ user_lookup }}`, etc.).

### Nested template expressions

`{{ {{ foo }}.bar }}` doesn't work; templates don't compose. If you need dynamic path access, compute the full path in an upstream Transform node and store it as a single string variable.

### JSON syntax with templates

In a Response node's body or any other JSON field:

* `"value": "{{ someStep }}"` works; quotes mark this as a string-or-object slot, the resolver preserves type if the whole value is one template
* `"value": {{ someStep }}` breaks the JSON parser in the editor; wrap templates that fill whole values in quotes

***

## Path syntax cheat sheet

| Expression                   | What it resolves to                                     |
| ---------------------------- | ------------------------------------------------------- |
| `{{ input }}`                | the whole trigger payload                               |
| `{{ input.user.name }}`      | nested object access                                    |
| `{{ input.items[0] }}`       | array index                                             |
| `{{ input.items[0].price }}` | nested index + field                                    |
| `{{ step_name }}`            | whole output of a step with `outputVariable: step_name` |
| `{{ step_name.field }}`      | field inside that step's output                         |

Identifiers may contain letters, digits, underscores, hyphens, and dots. Array brackets use numeric indices.
