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

# Using Template Expressions

> Understand how template expressions work across systems, tools, and steps.

Most of the time you don't have to write template expressions yourself—the agent generates them for you. Still, understanding how they work helps when you're debugging or tweaking a tool.

At their core, template expressions use the `<<expression>>` pattern, where `expression` is evaluated at runtime.

## Where template expressions are used

The same template engine is used across superglue:

* **Systems** – connection strings and URL templates
* **Step configuration** – `urlHost`, `urlPath`, `headers`, `queryParams`, `body`
* **Transforms** – final transforms and data selectors

## Template expression modes

There are two kinds of template expressions: **simple expressions** and **arrow function expressions**.

### Simple expressions (legacy)

Simple expressions resolve values directly from the context (payload, credentials, previous step results) without any JavaScript.

Syntax:

* `<<variable>>`

**Examples:**

In the context of a tool step:

```typescript theme={null}
headers: {
  "Authorization": "Bearer <<stripe_apiKey>>"
},
queryParams: {
  user_id: "<<userId>>"
}
```

or in a system:

```text theme={null}
postgres://<<username>>:<<password>>@<<host>>:<<port>>/<<database>>
```

### Arrow function expressions (recommended)

Arrow function expressions use JavaScript arrow functions that receive the context as a single parameter (typically named `sourceData`) and return the value to insert. superglue runs these functions in a sandboxed JavaScript VM.

```js theme={null}
<<(sourceData) => {
  // read from sourceData and return the value to insert
}>>
```

<Note>
  Arrow function expressions are also used in places that are pure code (for example, the
  `outputTransform` field), where you don’t wrap them in `<< >>`. They still receive the same
  `sourceData` context object and behave the same way.
</Note>

**Examples:**

```typescript theme={null}
headers: {
  "Authorization": "<<(sourceData) => `Bearer ${sourceData.credentials.apiKey}`>>"
}
```

```typescript theme={null}
body: {
  posts: "<<(sourceData) => {
    const fromJsonPlaceholder =
      (sourceData.fetchJsonPlaceholderPosts ?? []).map(p => ({
        id: p.id,
        title: p.title,
        source: 'jsonplaceholder'
      }));

    const fromDummyJson =
      (sourceData.fetchDummyJsonPosts?.posts ?? []).map(p => ({
        id: p.id,
        title: p.title,
        source: 'dummyjson'
      }));

    return [...fromJsonPlaceholder, ...fromDummyJson];
  }>>"
}
```

## Template context

Template expressions evaluate against a **context object** that depends on where they're used (step config, system, or transform).

* **Arrow function expressions** – context is passed as the function parameter (typically `sourceData`)
* **Simple expressions** – the string inside `<< >>` is resolved against the same context object

The context looks different depending on where the expression is used:

### System context

The context is built from the system credentials (for example, `username`, `password`, `access_token`).

The `sourceData` might look like this:

```json theme={null}
{
  "username": "db_user",
  "password": "secret123",
  "host": "db.example.com",
  "port": "5432",
  "database": "production"
}
```

<Note>
  System templates are only resolved at tool execution time and get merged
  with tool-specific credentials.
</Note>

### Tool step context

The context is the **aggregated step input**, which includes:

* `payload` – workflow input payload
* `credentials` – resolved credentials for the system
* Previous step results keyed by step ID (for example, `getCustomers`)
* `currentItem` – current iteration data when the step runs in a loop

The `sourceData` object might look like this:

```json theme={null}
{
  "payload": { "userId": "12345", "startDate": "2024-01-01" },
  "credentials": { "apiKey": "sk_test_..." },
  "getCustomers": {
    "data": [{ "id": "cus_123", "email": "user@example.com" }]
  }
}
```

### Pagination variables

When pagination is configured on a step, the following variables are available in the request configuration (`urlPath`, `queryParams`, `headers`, `body`):

| Variable   | Description                                          |
| ---------- | ---------------------------------------------------- |
| `page`     | Current page number (starts at 1)                    |
| `offset`   | Current offset (starts at 0, increments by pageSize) |
| `cursor`   | Cursor value extracted from the previous response    |
| `limit`    | Same as pageSize                                     |
| `pageSize` | The configured page size                             |

**Examples:**

Page-based pagination:

```typescript theme={null}
queryParams: {
  "page": "<<page>>",
  "per_page": "<<limit>>"
}
```

Offset-based pagination:

```typescript theme={null}
queryParams: {
  "offset": "<<offset>>",
  "limit": "<<limit>>"
}
```

Cursor-based pagination:

```typescript theme={null}
queryParams: {
  "cursor": "<<cursor>>",
  "limit": "<<pageSize>>"
}
```

### Stop condition

The stop condition is a JavaScript function that determines when to stop fetching pages. It receives two arguments:

1. **`response`** – object containing:
   * `data` – the parsed response body
   * `headers` – response headers

2. **`pageInfo`** – object containing:
   * `page` – current page number
   * `offset` – current offset
   * `cursor` – current cursor value
   * `totalFetched` – total number of items fetched so far

The function should return `true` to **stop** pagination, or `false` to continue.

**Examples:**

Stop when no more pages (using response metadata):

```javascript theme={null}
(response, pageInfo) => !response.data.has_more;
```

Stop when data array is empty:

```javascript theme={null}
(response, pageInfo) => response.data.items.length === 0;
```

Stop when cursor is null or missing:

```javascript theme={null}
(response, pageInfo) => !response.data.next_cursor;
```

Stop after fetching a specific number of items:

```javascript theme={null}
(response, pageInfo) => pageInfo.totalFetched >= 1000;
```

Stop when on last page (from total pages header):

```javascript theme={null}
(response, pageInfo) =>
  pageInfo.page >= parseInt(response.headers["x-total-pages"] || "1");
```

Combine multiple conditions:

```javascript theme={null}
(response, pageInfo) => {
  const items = response.data.results || [];
  return (
    items.length === 0 || !response.data.next || pageInfo.totalFetched >= 5000
  );
};
```

### Output transform context

The context is a combined view of the entire workflow execution:

* All step results keyed by step ID
* The original `payload`

The `sourceData` object might look like this:

```json theme={null}
{
  "payload": { "userId": "12345" },
  "getCustomers": {
    "data": [{ "id": "cus_123", "email": "user@example.com" }]
  },
  "createPaymentIntent": {
    "data": { "id": "pi_456", "status": "succeeded" }
  }
}
```
