Using Template Expressions
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
Section titled “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
Section titled “Template expression modes”There are two kinds of template expressions: simple expressions and arrow function expressions.
Simple expressions (legacy)
Section titled “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:
headers: { "Authorization": "Bearer <<stripe_apiKey>>"},queryParams: { user_id: "<<userId>>"}or in a system:
postgres://<<username>>:<<password>>@<<host>>:<<port>>/<<database>>Arrow function expressions (recommended)
Section titled “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.
<<(sourceData) => { // read from sourceData and return the value to insert}>>Examples:
headers: { "Authorization": "<<(sourceData) => `Bearer ${sourceData.credentials.apiKey}`>>"}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
Section titled “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
Section titled “System context”The context is built from the system credentials (for example, username, password, access_token).
The sourceData might look like this:
{ "username": "db_user", "password": "secret123", "host": "db.example.com", "port": "5432", "database": "production"}Tool step context
Section titled “Tool step context”The context is the aggregated step input, which includes:
payload– workflow input payloadcredentials– 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:
{ "payload": { "userId": "12345", "startDate": "2024-01-01" }, "credentials": { "apiKey": "sk_test_..." }, "getCustomers": { "data": [{ "id": "cus_123", "email": "user@example.com" }] }}Pagination variables
Section titled “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:
queryParams: { "page": "<<page>>", "per_page": "<<limit>>"}Offset-based pagination:
queryParams: { "offset": "<<offset>>", "limit": "<<limit>>"}Cursor-based pagination:
queryParams: { "cursor": "<<cursor>>", "limit": "<<pageSize>>"}Stop condition
Section titled “Stop condition”The stop condition is a JavaScript function that determines when to stop fetching pages. It receives three arguments:
-
response– object containing:data– the parsed response bodyheaders– response headers
-
pageInfo– object containing:page– current page numberoffset– current offsetcursor– current cursor valuetotalFetched– total number of items in the merged paginated result, including the current pagemergedResult– accumulated paginated result including the current page
-
sourceData– current step input data, with payload fields at the root plus previous step results
The function should return true to stop pagination, or false to continue.
Examples:
Stop when no more pages (using response metadata):
(response, pageInfo) => !response.data.has_more;Stop when data array is empty:
(response, pageInfo) => response.data.items.length === 0;Stop when cursor is null or missing:
(response, pageInfo) => !response.data.next_cursor;Stop after fetching a specific number of items:
(response, pageInfo) => pageInfo.totalFetched >= 1000;Stop after fetching the number of items requested by the tool input:
(response, pageInfo, sourceData) => pageInfo.totalFetched >= sourceData.maxResults;Stop when on last page (from total pages header):
(response, pageInfo) => pageInfo.page >= parseInt(response.headers["x-total-pages"] || "1");Combine multiple conditions:
(response, pageInfo) => { const items = response.data.results || []; return items.length === 0 || !response.data.next || pageInfo.totalFetched >= 5000;};Output transform context
Section titled “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:
{ "payload": { "userId": "12345" }, "getCustomers": { "data": [{ "id": "cus_123", "email": "user@example.com" }] }, "createPaymentIntent": { "data": { "id": "pi_456", "status": "succeeded" } }}