{{ ... }} inside a Flow Definition, the platform resolves the enclosed path against the execution’s context — trigger input, definition variables, prior step outputs — just before the task runs.
Where expressions can appear
Context roots
Every expression starts from one of these roots:var and account are distinct scopes. var is a constant local to a single definition; account is shared configuration your whole account owns and can change on the fly. See Account Variables for when to use which — and why secrets belong in a credential, never in either variable scope.Dot-path traversal
Paths use dots to walk into nested objects:{{input.contact.address.city}}. Traversal is null-safe — if any segment along the path is missing, the expression resolves to null instead of raising an error. In a mixed string template, a null value renders as an empty string.
To supply a fallback, use the default pipe:
true/false become booleans, bare numbers become numbers, and null stays null.
Pipes
A pipe reshapes a value on its way into a parameter — trim the whitespace off a name, normalize a phone number, round a cost to two places — without needing a whole step to do it. Write one after a| inside the braces:
Chaining
Pipes chain left to right, to any depth. Each one receives whatever the one before it produced:default, which only ever sees what reaches it:
Put
default after the pipe whose failure you want to catch, not before it.
Arguments
Arguments follow the pipe name after a colon, separated by commas:default’s fallback: quoted strings stay strings, true/false become booleans, bare numbers become numbers, and null stays null.
The full set
Texttruncate’s suffix is spent out of the length, not added to it: truncate: 20, '...' returns at most 20 characters including the ellipsis. Truncation is usually there to fit a provider’s column limit, and a suffix that pushed the value past that limit would defeat the pipe you wrote it for.
Dates
Both read ISO-8601 — a date, or a datetime with or without an offset. Anything else fails rather than being guessed at, so
08/23/2026 is refused instead of being read as one of the two dates it could mean.
dateAdd accepts seconds, minutes, hours, days and weeks, and deliberately not months or years. “One month after 31 January” has no single correct answer — 28 February, 29 February, 2 March and 3 March are all defensible — and approximating a month as 30 days would put a silently wrong date somewhere you would never look for it. A negative amount shifts backwards.toNumber returns a whole number when the value is integral, because 3.0 where 3 was meant is the kind of thing a provider rejects. true and false are refused rather than read as 1 and 0.
Encoding
urlEncode exempts nothing, / included — its job is to make a value safe as a single path or query segment, and a value containing a slash must not be able to escape that segment. base64Decode refuses text that is not valid base64 rather than quietly discarding the characters that do not belong.
Null safety
default substitutes only when the value is missing or an earlier pipe failed. A value that is present — including 0, false and an empty string — passes straight through untouched.
Phone numbers
This is the same normalizer the platform uses everywhere else a phone number is stored, so a number normalized in an expression and a number normalized on a data store write always agree. Correct shape is not enough — a well-formed string that is not a real number is refused.
What fails, and why
A pipe either produces a value or fails the step. There is no third outcome where a value quietly becomes empty and travels on:- A value that is present but cannot be transformed fails, with a reason that names the pipe —
toNumberon"abc",formatDateon text that is not a date,toE164on something that is not a number. The failure is immediate and is not retried, because running it again produces exactly the same result. - A value that is missing fails the same way entering any pipe other than
default, withvalue is missing. Attaching a pipe is how you declare that a value has to be there — there is no separate “required” marker to remember. - A bare path with no pipe still resolves to
null, exactly as it always has. Nothing you have already saved changes behaviour.
The escape hatch
| default: is how you say “and if that does not work, use this”. It catches both a missing value and a failed pipe earlier in the chain:
Type preservation
How a value resolves depends on whether the expression stands alone:- Whole-value expression — when the entire parameter value is a single
{{ ... }}, the resolved value keeps its native type: an object stays an object, an array stays an array, a number stays a number. This is how you pass structured data (like a list of records) from one step to the next without serializing it. - Mixed template — when an expression is embedded in surrounding text (
"Hello {{input.name}}"), the result is rendered as a string.
Conditions
Exit conditions compare two values with one of six operators:== != > < >= <=
true/false, or null. A condition with no operator at all is evaluated for truthiness: it passes if the expression resolves to a truthy value.
The ordering operators (
>, <, >=, <=) require both sides to be numeric; if either side can’t be treated as a number, the condition evaluates to false. Equality (==, !=) works on any types.Validation at creation time
When you create a definition, every string in the body is scanned for malformed expressions. If any are found, the request is rejected with422 and a list of the problems:
- Unclosed expressions — a
{{with no matching}}. - Unknown pipe operators — a pipe name that is not one of the sixteen above. Every stage of a chain is checked, not just the first, so a misspelling in the last position is caught at save time rather than at run time.
- The wrong number of arguments for a pipe —
roundwith no places,replacewith only one,trimwith any at all. The error names the pipe, how many it expects and how many it was given. - Unbalanced quotes in an argument list — a
'or"that is never closed. - An unknown context root — including
row, which is accepted only inside a record transform step that works record by record, and rejected everywhere else. The error lists the roots that were available where you wrote it.
formatDate pattern is the one you intended, or a dateAdd unit is spelled correctly, is decided at run time. A validator that guessed at those would reject definitions that work.
Next steps
Flow definitions
Where inputs, variables, steps, and tasks are declared.
Execution models
Immediate, scheduled, windowed, and signaled tasks.
Record transforms
Reshape a whole set of records — deduplicate, filter, sort, map fields.
Catalog
Every action’s full parameter and output reference.