Template Syntax

Template expressions let you pass data between nodes, read workflow context, and transform values at runtime. Write JSONata expressions inside double curly brace delimiters.

Expression syntax

All template expressions use double curly braces with a JSONata expression inside:

{{ expression }}

Expressions are resolved at runtime, just before each node executes. Any string value in a node's URL, headers, or body can contain template expressions.

Basic expressions

'{{ context.userId }}'                       // read from workflow context
'{{ results.get_user.data.name }}'           // read from a completed node
'{{ $secret("api_key") }}'                   // read a secret
'{{ results.get_order.data.total * 1.1 }}'   // compute a value

Data sources

Four data sources are available inside template expressions:

SourceSyntaxDescription
Node resultsresults.nodeId.data.fieldHTTP response body from a completed upstream node
Contextcontext.keyGlobal data passed when executing the workflow
Rowrow.data.column / row.indexCurrent row in iterator child workflows
Secrets$secret('name')Credential resolved at runtime from your secrets vault

Accessing node results

When a node completes, its result is stored with three fields:

FieldTypeDescription
dataanyThe HTTP response body
statusCodenumberThe HTTP status code (e.g. 200, 404)
headersobjectThe response headers

If a node called get_user returns this response body:

Response from get_user

{
  "id": 123,
  "name": "Alice",
  "email": "alice@example.com"
}

Access its fields like this:

Accessing result fields

'{{ results.get_user.data.id }}'              // 123
'{{ results.get_user.data.name }}'            // "Alice"
'{{ results.get_user.data.email }}'           // "alice@example.com"
'{{ results.get_user.statusCode }}'           // 200
'{{ results.get_user.headers.content-type }}' // "application/json"

Using templates in nodes

Templates work in URLs, headers, and request bodies. Here is a node that uses all three:

import { GraphCompose } from '@graph-compose/client'

const graph = new GraphCompose({
  token: process.env.GRAPH_COMPOSE_TOKEN
})

graph
  .node('get_user')
    .get('https://api.example.com/users/{{ context.userId }}')
  .end()

  .node('create_order')
    .post('https://api.example.com/orders')
    .withHeaders({
      'Authorization': 'Bearer {{ $secret("api_token") }}'
    })
    .withBody({
      userId: '{{ results.get_user.data.id }}',
      name: '{{ results.get_user.data.name }}',
      discount: '{{ results.get_user.data.loyaltyPoints > 1000 ? 0.1 : 0 }}'
    })
    .withDependencies(['get_user'])
  .end()

Embedded expressions

You can mix literal text with template expressions in a single string. This is common in URLs and header values.

Embedded expressions

// URL with path parameter
'https://api.example.com/users/{{ context.userId }}/orders'

// Authorization header
'Bearer {{ results.auth.data.token }}'

// Multiple expressions in one string
'https://api.example.com/{{ context.version }}/users/{{ results.get_user.data.id }}'

Transforming data with JSONata

The expression language inside template delimiters is JSONata, a query and transformation language for JSON. Beyond simple field access, you can filter arrays, aggregate values, and reshape objects.

Filtering

// Get only active orders
'{{ results.get_orders.data[status = "active"] }}'

// Get names of items over $50
'{{ results.get_items.data[price > 50].name }}'

Aggregation

// Sum all item prices
'{{ $sum(results.get_orders.data.items.price) }}'

// Count completed orders
'{{ $count(results.get_orders.data[status = "completed"]) }}'

// Get the most expensive item
'{{ $max(results.get_items.data.price) }}'

Conditionals

// Ternary expression
'{{ results.check.data.amount > 100 ? "large" : "small" }}'

// Boolean check
'{{ results.get_user.data.verified = true }}'

Object projection

// Reshape array items into a new structure
'{{ results.get_cart.data.items.{ "productId": id, "total": price * quantity } }}'

Supported functions

Graph Compose supports the following JSONata built-in functions. Functions not listed here are blocked during validation.

CategoryFunctions
String$string, $length, $substring, $substringBefore, $substringAfter, $uppercase, $lowercase, $trim, $pad, $contains, $split, $join, $match, $replace
Encoding$base64encode, $base64decode, $encodeUrlComponent, $encodeUrl, $decodeUrlComponent, $decodeUrl
Numeric$number, $sum, $max, $min, $average, $round, $power, $sqrt, $abs, $floor, $ceil
Date/Time$now, $millis, $fromMillis, $toMillis
Boolean$boolean, $not, $exists
Array$count, $append, $sort, $reverse, $shuffle, $distinct, $zip, $map, $filter, $reduce, $first, $last, $single
Object$keys, $lookup, $spread, $sift, $each, $merge, $type

Next steps