Expressions
The {{ }} expression language - how data flows between nodes, and the 91 functions you can call inside an expression.
Any field with the expression marker accepts {{ }} expressions. Inside the
braces you can read anything the run has produced so far, and transform it
with the functions below.
Reading data
An expression's simplest form is a path into the run context:
{{webhook.email}}
{{lookup.httpResponse.status}}
{{vars.apiBase}}Every node writes its output under its own variableName, so a node named
lookup is readable downstream as {{lookup...}}. See
Workflows for the full context model.
Start typing {{ in any expression field and the editor offers the data
your upstream nodes actually produced, plus every function on this page, with
its call shape and a worked example. Hovering a finished expression shows the
value it currently resolves to.
Calling a function
A function is written first inside the braces, with its arguments after it, separated by spaces - not commas, and not parentheses around the whole call:
{{upper contact.name}}
{{dateFormat order.createdAt "yyyy-MM-dd"}}
{{join (pluck order.lineItems "sku") ", "}}Nest a call inside another by wrapping it in parentheses, as pluck is
above. String arguments need quotes; numbers and paths do not.
Two rules worth knowing:
- Your data always wins. If a function shares a name with one of your
fields, a bare
{{sum}}still resolves your field. The function only takes over when you call it with an argument:{{sum order.lineItems "amount"}}. Adding functions can never change what an existing workflow resolves to. - Nothing throws. A function given something it cannot use resolves to an empty string rather than failing the run, the same as a malformed template or a path that doesn't exist.
Conditionals and loops
Handlebars' own block syntax works everywhere too, and the comparison functions below are what you put inside it:
{{#if (gt order.total 100)}}Free shipping{{else}}Standard shipping{{/if}}
{{#each order.lineItems}}{{this.sku}} x{{this.qty}}
{{/each}}Function reference
Text
| Function | What it does | Example | Result |
|---|---|---|---|
upper text | Uppercases the text. | {{upper contact.name}} | ADA LOVELACE |
lower text | Lowercases the text. | {{lower contact.email}} | ada@example.com |
trim text | Removes leading and trailing whitespace. | {{trim form.comment}} | looks good |
capitalize text | Uppercases the first character only. | {{capitalize status}} | Shipped |
titleCase text | Uppercases the first letter of every word. | {{titleCase product.name}} | Blue Widget |
replace text search replacement | Replaces every occurrence of a substring. | {{replace order.sku "-" "_"}} | SKU_1024 |
split text separator | Splits text into an array on a separator. | {{split tags ","}} | [urgent, billing] |
substring text start [end] | Characters between two zero-based positions. | {{substring order.id 0 8}} | ord_9f2a |
truncate text length [suffix] | Shortens text, appending "…" (or your suffix) if it was cut. | {{truncate issue.body 80}} | The checkout page throws a 500 when the cart is… |
padStart text length [char] | Pads the front of the text to a fixed width. | {{padStart invoice.number 6 "0"}} | 000042 |
padEnd text length [char] | Pads the end of the text to a fixed width. | {{padEnd label 10 "."}} | Total..... |
repeat text count | Repeats the text n times. | {{repeat "-" 20}} | -------------------- |
concat a b [c…] | Joins any number of values into one string. | {{concat contact.first " " contact.last}} | Ada Lovelace |
slugify text | Lowercase, hyphenated, URL-safe form of the text. | {{slugify post.title}} | shipping-the-new-editor |
urlEncode text | Percent-encodes the text for use in a URL or query string. | {{urlEncode search.term}} | blue%20widget |
urlDecode text | Reverses percent-encoding. | {{urlDecode webhook.query.q}} | blue widget |
base64Encode text | Base64-encodes the text (UTF-8 safe). | {{base64Encode (concat user ":" token)}} | YWRhOnNlY3JldA== |
base64Decode text | Decodes base64 back to text. | {{base64Decode payload.data}} | hello |
stripHtml html | Removes HTML tags, leaving the text content. | {{stripHtml email.bodyHtml}} | Your order has shipped |
startsWith text prefix | True when the text begins with the prefix. | {{#if (startsWith email "admin@")}}internal{{/if}} | internal |
endsWith text suffix | True when the text ends with the suffix. | {{#if (endsWith file.name ".pdf")}}pdf{{/if}} | pdf |
matches text pattern [flags] | True when the regular expression matches the text. | {{#if (matches phone "^\+1")}}US{{/if}} | US |
regexExtract text pattern [group] | Returns the first regex match, or a capture group of it. | {{regexExtract subject "#(\d+)" 1}} | 4821 |
regexReplace text pattern replacement [flags] | Regex replace; defaults to global. Use "$1" for groups. | {{regexReplace sku "[^0-9]" ""}} | 1024 |
Numbers
| Function | What it does | Example | Result |
|---|---|---|---|
add a b [c…] | Adds numbers together. | {{add order.subtotal order.shipping}} | 42.5 |
subtract a b | Subtracts b from a. | {{subtract order.total order.discount}} | 37.5 |
multiply a b [c…] | Multiplies numbers together. | {{multiply item.price item.quantity}} | 59.97 |
divide a b | Divides a by b; dividing by zero gives an empty value. | {{divide total count}} | 12.5 |
modulo a b | Remainder of a divided by b. | {{modulo index 2}} | 1 |
round value [decimals] | Rounds to the nearest whole number, or to n decimals. | {{round score 1}} | 8.7 |
floor value | Rounds down to a whole number. | {{floor cart.weight}} | 3 |
ceil value | Rounds up to a whole number. | {{ceil cart.weight}} | 4 |
abs value | Absolute value. | {{abs balance.delta}} | 19.99 |
toFixed value decimals | Formats a number with a fixed number of decimals. | {{toFixed order.total 2}} | 37.50 |
toNumber value | Parses text into a number ("1,024" reads as 1024). | {{toNumber webhook.body.amount}} | 1024 |
min a b [c…] | min array | Smallest of the values, or of an array. | {{min prices}} | 4.99 |
max a b [c…] | max array | Largest of the values, or of an array. | {{max prices}} | 29.99 |
sum array [field] | Adds up an array, optionally a field on each item. | {{sum order.lineItems "amount"}} | 59.97 |
avg array [field] | Mean of an array, optionally of a field on each item. | {{round (avg reviews "rating") 2}} | 4.35 |
clamp value min max | Keeps a number inside a range. | {{clamp quantity 1 10}} | 10 |
Dates and times
| Function | What it does | Example | Result |
|---|---|---|---|
now | The current time as an ISO 8601 string. Write it as "(now)" when passing it to another helper. | {{dateFormat (now) "date"}} | 2026-07-27 |
dateFormat date pattern [timezone] | Formats a date. Patterns: date-fns tokens, or "date"/"time"/"datetime"/"iso"/"us"/"eu"/"long"/"human". | {{dateFormat order.createdAt "human" "America/New_York"}} | 27 Jul 2026, 05:15 |
dateAdd date amount unit | Adds time to a date. Units: year, month, week, day, hour, minute, second. | {{dateFormat (dateAdd (now) 3 "days") "date"}} | 2026-07-30 |
dateSubtract date amount unit | Subtracts time from a date. Same units as dateAdd. | {{dateFormat (dateSubtract (now) 1 "week") "date"}} | 2026-07-20 |
dateDiff from to [unit] | Whole units between two dates, counting forward from "from". Defaults to days. | {{dateDiff subscription.startedAt (now) "days"}} | 34 |
startOf date unit | Start of the containing year / month / week / day / hour / minute, in UTC. | {{dateFormat (startOf (now) "month") "date"}} | 2026-07-01 |
endOf date unit | End of the containing period, in UTC. Same units as startOf. | {{dateFormat (endOf (now) "month") "date"}} | 2026-07-31 |
toIso date | Converts any recognisable date into ISO 8601. | {{toIso webhook.body.timestamp}} | 2026-07-27T09:15:00.000Z |
toUnix date | Unix timestamp in seconds. | {{toUnix (now)}} | 1785316500 |
fromUnix seconds | Turns a unix timestamp into an ISO date. | {{dateFormat (fromUnix stripe.created) "datetime"}} | 2026-07-27 09:15:00 |
isBefore a b | True when date a is earlier than date b. | {{#if (isBefore trial.endsAt (now))}}expired{{/if}} | expired |
isAfter a b | True when date a is later than date b. | {{#if (isAfter invoice.dueAt (now))}}not due yet{{/if}} | not due yet |
Arrays
| Function | What it does | Example | Result |
|---|---|---|---|
length value | Item count of an array, characters of a string, keys of an object. | {{length order.lineItems}} | 3 |
first array [count] | First item, or the first n items. | {{first search.results}} | { id: 1 } |
last array [count] | Last item, or the last n items. | {{last messages}} | { id: 9 } |
join array [separator] | Joins an array into text. Separator defaults to ", ". | {{join (pluck contacts "email") "; "}} | ada@example.com; alan@example.com |
pluck array field | Pulls one field out of every item into a new array. | {{pluck order.lineItems "sku"}} | [SKU-1, SKU-2] |
where array field value | Keeps the items whose field equals a value. | {{length (where issues "state" "open")}} | 7 |
sortBy array [field] ["asc"|"desc"] | Sorts an array, optionally by a field on each item. | {{first (sortBy deals "amount" "desc")}} | { amount: 92000 } |
unique array [field] | Removes duplicates, comparing a field when given one. | {{length (unique orders "customerId")}} | 12 |
reverse array | Reverses the order of an array. | {{join (reverse steps)}} | three, two, one |
slice array start [end] | A sub-range of an array, by zero-based position. | {{slice search.results 0 5}} | […5 items] |
flatten array [depth] | Flattens nested arrays into one. | {{join (flatten (pluck orders "tags"))}} | urgent, billing, vip |
compact array | Drops empty, null and undefined items. | {{join (compact (pluck contacts "phone"))}} | +15551234567 |
chunk array size | Splits an array into batches of a fixed size. | {{length (chunk recipients 50)}} | 4 |
range start end [step] | An array of numbers from start up to (not including) end. | {{#each (range 1 4)}}{{this}} {{/each}} | 1 2 3 |
contains haystack needle | True when an array holds the item, or text holds the substring. | {{#if (contains issue.labels "bug")}}triage{{/if}} | triage |
indexOf haystack needle | Zero-based position of an item or substring, or -1. | {{indexOf tags "urgent"}} | 0 |
Objects
| Function | What it does | Example | Result |
|---|---|---|---|
get object path [fallback] | Reads a nested path ("a.b[0].c"), with an optional fallback. | {{get webhook.body "customer.address.city" "unknown"}} | Lisbon |
has object path | True when the path exists and is not null. | {{#if (has payload "customer.vatId")}}b2b{{/if}} | b2b |
keys object | The object's own property names, as an array. | {{join (keys webhook.body)}} | id, email, plan |
values object | The object's values, as an array. | {{join (values counts)}} | 3, 7, 12 |
pick object key [key…] | A copy of the object with only the named keys. | {{json (pick contact "email" "name")}} | { "email": "…", "name": "…" } |
omit object key [key…] | A copy of the object without the named keys. | {{json (omit webhook.body "password")}} | { "email": "…" } |
json value | Pretty-printed JSON, safe to drop into a request body. | {{json webhook.body}} | { "id": 1 } |
stringify value | Compact single-line JSON. | {{stringify order.lineItems}} | [{"sku":"SKU-1"}] |
jsonParse text [path] | Parses JSON text, optionally reading a path out of it. | {{jsonParse http.body "data.0.id"}} | 42 |
typeOf value | One of "string", "number", "boolean", "array", "object", "null". | {{typeOf webhook.body.items}} | array |
Logic and comparison
| Function | What it does | Example | Result |
|---|---|---|---|
eq a b | True when the values match ("5" and 5 count as equal). | {{#if (eq order.status "paid")}}fulfil{{/if}} | fulfil |
ne a b | True when the values differ. | {{#if (ne user.plan "free")}}priority{{/if}} | priority |
gt a b | True when a is greater than b. | {{#if (gt order.total 100)}}free shipping{{/if}} | free shipping |
gte a b | True when a is greater than or equal to b. | {{#if (gte score 90)}}A{{/if}} | A |
lt a b | True when a is less than b. | {{#if (lt stock 5)}}reorder{{/if}} | reorder |
lte a b | True when a is less than or equal to b. | {{#if (lte age 17)}}minor{{/if}} | minor |
and a b [c…] | True when every value is truthy. | {{#if (and user.email user.consent)}}send{{/if}} | send |
or a b [c…] | True when any value is truthy. | {{#if (or issue.urgent issue.escalated)}}page{{/if}} | page |
not value | Inverts a value's truthiness. | {{#if (not user.verified)}}remind{{/if}} | remind |
ifElse condition whenTrue whenFalse | Inline choice between two values. | {{ifElse user.name user.name "there"}} | there |
coalesce a b [c…] | The first value that is not empty, null or undefined. | {{coalesce contact.nickname contact.firstName contact.email}} | ada@example.com |
fallback value replacement | Uses the replacement when the value is empty. | {{fallback lead.company "Unknown company"}} | Unknown company |
isEmpty value | True for empty text, empty arrays, empty objects, null and undefined. | {{#if (isEmpty search.results)}}nothing found{{/if}} | nothing found |
Related
- Workflows - the context object every expression reads from.
- Flow control - Branch conditions, which are expressions too.
- Tables and variables -
{{vars.X}}and data tables.