Power Automate Expression Syntax: Complete Cheat Sheet (2026)
Power Automate expression syntax: 60+ copy-paste formulas for strings, dates, arrays and logic. Covers @{} inline form, null safety, and common error fixes.

Power Automate expression syntax is the formula language used inside flow actions — the same Workflow Definition Language (WDL) engine that runs Azure Logic Apps (Microsoft Learn, 2026). You write expressions in the expression editor tab of any action input field: click the field, select "Expression", type your function, and click OK. The result replaces the field value at run time.
Two forms exist. Inline — @{functionName(args)} — embeds the result inside a string, so Hello @{triggerOutputs()?['body/Name']} produces Hello Rizwan. Pure expression — just functionName(args) with no @{} wrapper — returns the raw value and is what you use in the expression editor. Mixing them in the same field causes parser errors.
Key Takeaways
- Power Automate expressions use Workflow Definition Language (WDL) — the same engine as Azure Logic Apps (Microsoft Learn, 2026).
- Use@{...}only for inline string interpolation; use barefunctionName()in the expression editor tab.
- The?operator makes any property access null-safe:body('Get_item')?['value']never throws on a missing field.
- coalesce() is the fastest fix for null values from SharePoint, Dataverse, or HTTP responses.- All 60+ functions in this cheat sheet are copy-paste ready with live examples.
---
Expression Syntax Basics
Power Automate expressions follow a strict parser. Get these rules wrong and you'll see InvalidTemplate before the flow even runs.
The two forms
# Pure expression (use in the Expression tab):
concat('Hello', ' ', triggerOutputs()?['body/Name'])# Inline interpolation (embed inside a text field):
Hello @{triggerOutputs()?['body/Name']}, your order is @{outputs('Get_order')?['body/Status']}
Never wrap a pure expression in @{...} in the expression editor — the parser will double-evaluate it and produce a string that starts with a literal @.
Quote rules
Single quotes delimit string literals. Double quotes are not valid inside expressions and will break the parser:
# Correct
replace(triggerOutputs()?['body/Title'], 'Draft', 'Final')# Broken — double quotes cause InvalidTemplate
replace(triggerOutputs()?["body/Title"], "Draft", "Final")
To include a literal single quote in a string, escape it by doubling: 'O''Brien'.
Null safety with ?
The ? operator on a property access returns null instead of throwing when the property doesn't exist. Use it on every dynamic content reference:
# Throws if 'Manager' is null in SharePoint People column
triggerOutputs()?['body/Manager/Email']# Safe — returns null instead of crashing
triggerOutputs()?['body/Manager']?['Email']
Chain as many ? as you need. Combine with coalesce() to substitute a default when null comes through.
Operator precedence
Power Automate expressions don't support infix math operators (+, -, *, /). Use functions: add(), sub(), mul(), div(), mod(). Parentheses control evaluation order inside function arguments exactly as you'd expect.
How to test any expression
Drop a Compose action into your flow, paste the expression in its input, and run the flow. The Compose output shows exactly what the expression returns — invaluable before wiring a complex expression into a Send Email or Condition action.
---
Power Automate Expressions List (All Functions A–Z)
Quick index — every function covered in this post, alphabetically. Click any category header to jump to the full table.
| Function | Category | Returns |
|---|---|---|
add | Math | Sum of two numbers |
addDays | Date/Time | Timestamp ± N days |
addHours | Date/Time | Timestamp ± N hours |
addMinutes | Date/Time | Timestamp ± N minutes |
addSeconds | Date/Time | Timestamp ± N seconds |
and | Logic | true if all conditions true |
base64 | Conversion | Base64-encoded string |
base64ToString | Conversion | Decoded UTF-8 string |
bool | Conversion | Boolean true/false |
chunk | Array | Array split into sub-arrays |
coalesce | Logic | First non-null value |
concat | String | Joined strings |
contains | String / Array | true if item found |
convertTimeZone | Date/Time | Timestamp in target time zone |
createArray | Array | New array |
dateDifference | Date/Time | Difference as duration |
dayOfMonth | Date/Time | Day number (1–31) |
dayOfWeek | Date/Time | Day number (0=Sunday) |
decodeBase64 | Conversion | Decoded string |
decodeUriComponent | Conversion | URL-decoded string |
div | Math | Quotient (integer) |
empty | Logic | true if null/empty |
endsWith | String | true if ends with |
equals | Logic | true if values equal |
first | Array | First element |
float | Conversion | Floating-point number |
formatDateTime | Date/Time | Formatted date string |
formatNumber | String | Formatted number string |
getFutureTime | Date/Time | Timestamp N units from now |
getPastTime | Date/Time | Timestamp N units ago |
greater | Logic | true if value1 > value2 |
greaterOrEquals | Logic | true if value1 >= value2 |
if | Logic | Conditional value |
indexOf | String | Position of substring |
int | Conversion | Integer |
intersection | Array | Common items |
join | Array | Array joined to string |
json | Conversion | Parsed JSON object |
last | Array | Last element |
length | String / Array | Count |
less | Logic | true if value1 < value2 |
lessOrEquals | Logic | true if value1 <= value2 |
mod | Math | Remainder |
mul | Math | Product |
not | Logic | Negated boolean |
nthIndexOf | String | Nth occurrence position |
or | Logic | true if any condition true |
replace | String | String with substitutions |
reverse | Array | Reversed array |
skip | Array | Array minus first N |
sort | Array | Sorted array |
split | String | Array from split |
startsWith | String | true if starts with |
string | Conversion | String representation |
sub | Math | Difference |
substring | String | Substring by index |
take | Array | First N elements |
ticks | Date/Time | Tick count (100-ns units) |
toLower | String | Lowercase string |
toUpper | String | Uppercase string |
trim | String | Whitespace-trimmed string |
union | Array | Merged array (deduped) |
uriComponent | Conversion | URL-encoded string |
xml | Conversion | XML object |
All functions are documented at Microsoft Learn — Workflow Definition Language Functions Reference.
---
String Functions
Power Automate provides 16 string functions covering concatenation, search, replacement, padding, and formatting. These are the functions you'll use in nearly every flow that handles user data, file names, or email content — all documented in the Microsoft Learn WDL reference.
| Function | Syntax | Example | Output |
|---|---|---|---|
| concat | concat(text1, text2, ...) | concat('Hello', ' ', 'World') | Hello World |
| substring | substring(text, startIndex, length) | substring('PowerAutomate', 5, 8) | Automate |
| replace | replace(text, oldText, newText) | replace('Hello World', 'World', 'Flow') | Hello Flow |
| split | split(text, delimiter) | split('a;b;c', ';') | ["a","b","c"] |
| toLower | toLower(text) | toLower('HELLO') | hello |
| toUpper | toUpper(text) | toUpper('hello') | HELLO |
| trim | trim(text) | trim(' hello ') | hello |
| indexOf | indexOf(text, searchText) | indexOf('Hello World', 'World') | 6 |
| nthIndexOf | nthIndexOf(text, searchText, n) | nthIndexOf('a.b.c.d', '.', 2) | 3 |
| length | length(text) | length('Power') | 5 |
| startsWith | startsWith(text, searchText) | startsWith('PowerAutomate', 'Power') | true |
| endsWith | endsWith(text, searchText) | endsWith('report.pdf', '.pdf') | true |
| contains | contains(text, searchText) | contains('Hello World', 'World') | true |
| formatNumber | formatNumber(number, format) | formatNumber(1234.5, 'C2') | $1,234.50 |
String tips
Use concat() instead of the @{...} inline syntax when combining more than two dynamic values — it's easier to debug. When checking user input, always wrap in toLower() or toUpper() first so comparisons are case-insensitive. Use nthIndexOf() to locate the second or third occurrence of a delimiter (e.g., finding the second dot in a version string like 1.20.3).
Power Automate cloud flows don't have a native padLeft() expression — use formatNumber() instead for zero-padded integers: formatNumber(triggerOutputs()?['body/ID'], '000000') turns 42 into 000042. For arbitrary string padding, the workaround is substring(concat('000000', string(triggerOutputs()?['body/ID'])), sub(length(concat('000000', string(triggerOutputs()?['body/ID']))), 6)).
---
Date and Time Functions
Power Automate stores every timestamp internally as UTC. These 13 functions handle formatting, arithmetic, and time-zone conversion — the three tasks you'll need for every flow that touches dates in emails, SharePoint columns, or approval deadlines. The formatDateTime() format strings follow the .NET DateTimeFormat conventions (Microsoft Learn).
| Function | Syntax | Example | Output |
|---|---|---|---|
| utcNow | utcNow(format?) | utcNow('yyyy-MM-dd') | 2026-06-24 |
| addDays | addDays(timestamp, days, format?) | addDays(utcNow(), 7, 'yyyy-MM-dd') | 7 days from now |
| addHours | addHours(timestamp, hours, format?) | addHours(utcNow(), -3) | 3 hours ago |
| addMinutes | addMinutes(timestamp, minutes) | addMinutes(utcNow(), 30) | 30 min from now |
| addSeconds | addSeconds(timestamp, seconds) | addSeconds(utcNow(), 90) | 90 seconds from now |
| formatDateTime | formatDateTime(timestamp, format) | formatDateTime(utcNow(), 'MM/dd/yyyy') | 06/24/2026 |
| convertTimeZone | convertTimeZone(timestamp, source, dest, format?) | convertTimeZone(utcNow(), 'UTC', 'Eastern Standard Time', 'hh:mm tt') | 08:30 AM |
| getPastTime | getPastTime(interval, timeUnit, format?) | getPastTime(7, 'Day', 'yyyy-MM-dd') | 7 days ago |
| getFutureTime | getFutureTime(interval, timeUnit, format?) | getFutureTime(1, 'Month', 'yyyy-MM-dd') | 1 month from now |
| dayOfWeek | dayOfWeek(timestamp) | dayOfWeek('2026-06-24') | 3 (Wednesday) |
| dayOfMonth | dayOfMonth(timestamp) | dayOfMonth('2026-06-24') | 24 |
| ticks | ticks(timestamp) | ticks('2026-01-01') | Tick count |
| dateDifference | dateDifference(startDate, endDate) | dateDifference('2026-01-01', '2026-06-24') | 174.00:00:00 |
Date tips
formatDateTime() uses .NET custom date format strings. Common patterns: yyyy-MM-dd for ISO, MM/dd/yyyy for US, dd/MM/yyyy for EU, dddd, MMMM d, yyyy for display. Always convert to the user's time zone with convertTimeZone() before including dates in emails — Power Automate stores every timestamp as UTC internally.
getPastTime and getFutureTime are cleaner than addDays(utcNow(), -7) when you want a fixed offset from now. Valid timeUnit values: Second, Minute, Hour, Day, Week, Month, Year.
Use ticks() to compare two dates numerically — subtract them, then divide by 864000000000 to get days:
div(sub(ticks(outputs('DueDate')), ticks(utcNow())), 864000000000)---
Collection and Array Functions
Power Automate has 14 collection and array functions. They work on arrays returned by "List rows", "Get items", and HTTP responses — anywhere a multi-value result comes back and needs filtering, slicing, or merging before the next action. The PnP community maintains real-world examples of these patterns in SharePoint flows at PnP Samples if you need more context beyond this reference.
| Function | Syntax | Example | Output |
|---|---|---|---|
| first | first(collection) | first(createArray('a','b','c')) | a |
| last | last(collection) | last(createArray('a','b','c')) | c |
| length | length(collection) | length(createArray('a','b','c')) | 3 |
| contains | contains(collection, value) | contains(createArray('a','b'), 'b') | true |
| join | join(collection, delimiter) | join(createArray('a','b','c'), '; ') | a; b; c |
| split | split(text, delimiter) | split('a,b,c', ',') | ["a","b","c"] |
| union | union(collection1, collection2) | union(createArray(1,2), createArray(2,3)) | [1,2,3] |
| intersection | intersection(col1, col2) | intersection(createArray(1,2,3), createArray(2,3,4)) | [2,3] |
| skip | skip(collection, count) | skip(createArray('a','b','c'), 1) | ["b","c"] |
| take | take(collection, count) | take(createArray('a','b','c'), 2) | ["a","b"] |
| createArray | createArray(item1, item2, ...) | createArray(1, 2, 3) | [1,2,3] |
| reverse | reverse(collection) | reverse(createArray(1,2,3)) | [3,2,1] |
| sort | sort(collection, sortBy?) | sort(createArray(3,1,2)) | [1,2,3] |
| chunk | chunk(collection, size) | chunk(createArray(1,2,3,4,5), 2) | [[1,2],[3,4],[5]] |
Array tips
Use empty() to check if an array has items before looping. Combine skip() and take() for pagination. union() also merges two objects (not just arrays), which is useful for building dynamic JSON payloads.
chunk() is useful when you need to process a large SharePoint list in batches — split the ID array with chunk(), then loop over each sub-array. sort() works on arrays of strings or numbers; for complex objects, sort inside a Select + Apply to Each combination. reverse() is handy when you want the most recent item from a sorted list without reversing the sort order in a query.
---
Logical Functions
| Function | Syntax | Example | Output |
|---|---|---|---|
| if | if(expression, valueIfTrue, valueIfFalse) | if(equals(1,1), 'yes', 'no') | yes |
| equals | equals(value1, value2) | equals(toLower('Hello'), 'hello') | true |
| and | and(expr1, expr2) | and(greater(5,3), less(5,10)) | true |
| or | or(expr1, expr2) | or(equals(1,2), equals(1,1)) | true |
| not | not(expression) | not(equals(1,2)) | true |
| greater | greater(value1, value2) | greater(10, 5) | true |
| greaterOrEquals | greaterOrEquals(value1, value2) | greaterOrEquals(5, 5) | true |
| less | less(value1, value2) | less(3, 5) | true |
| lessOrEquals | lessOrEquals(value1, value2) | lessOrEquals(5, 5) | true |
| empty | empty(value) | empty('') | true |
| coalesce | coalesce(value1, value2, ...) | coalesce(null, null, 'default') | default |
Logic tips
Don't nest if() more than two levels deep — it becomes unreadable and hard to debug. Use a Condition action instead for branching. coalesce() is the go-to fix for null values from SharePoint People columns, Dataverse lookups, and HTTP responses — it returns the first non-null value. You can use it to provide fallbacks for optional fields without a separate null check:
coalesce(triggerOutputs()?['body/Manager/Email'], triggerOutputs()?['body/Owner/Email'], 'admin@contoso.com')---
Math Functions
Power Automate has no infix operators — there is no +, -, *, or / syntax. Every arithmetic operation requires an explicit function call. This surprises developers coming from Excel formulas or Power Fx, but the WDL parser simply doesn't support operator notation (Microsoft Learn).
| Function | Syntax | Example | Output |
|---|---|---|---|
| add | add(num1, num2) | add(10, 5) | 15 |
| sub | sub(num1, num2) | sub(10, 5) | 5 |
| mul | mul(num1, num2) | mul(4, 3) | 12 |
| div | div(num1, num2) | div(10, 3) | 3 (integer) |
| mod | mod(num1, num2) | mod(10, 3) | 1 |
Math tips
div() performs integer division — div(10, 3) returns 3, not 3.333. To get a float result, convert one operand first: div(float(10), 3). Chain functions for compound calculations: add(mul(3, 4), mod(10, 3)) gives 13. For percentage calculations, use mul(div(float(part), float(total)), 100) — the float() conversions are required or the intermediate div() will truncate.
---
Conversion Functions
Type mismatches are the most common cause of InvalidTemplate and ExpressionEvaluationFailed errors in production flows. These 11 functions handle every type conversion you'll need — between strings, numbers, booleans, JSON, XML, and encoded formats. When in doubt, call string() before passing a value to a string function or int() before arithmetic.
| Function | Syntax | Example | Output |
|---|---|---|---|
| int | int(value) | int('42') | 42 |
| float | float(value) | float('3.14') | 3.14 |
| string | string(value) | string(42) | "42" |
| bool | bool(value) | bool(1) | true |
| json | json(value) | json('{"name":"test"}') | JSON object |
| xml | xml(value) | xml(' | XML object |
| base64 | base64(value) | base64('Hello') | SGVsbG8= |
| base64ToString | base64ToString(value) | base64ToString('SGVsbG8=') | Hello |
| decodeBase64 | decodeBase64(value) | decodeBase64('SGVsbG8=') | Hello |
| uriComponent | uriComponent(value) | uriComponent('hello world') | hello%20world |
| decodeUriComponent | decodeUriComponent(value) | decodeUriComponent('hello%20world') | hello world |
Conversion tips
Use json() when an HTTP response body comes back as a string instead of a parsed object — this happens with some older REST APIs and SharePoint REST endpoints that return Content-Type: text/plain. Use xml() for SharePoint SOAP service responses. base64() and base64ToString() are commonly needed when working with attachment content in connectors like Outlook or OneDrive. uriComponent() is essential when you're building query string parameters dynamically — without it, spaces and special characters break the URL silently.
---
Common Production Patterns
These are the expressions you'll copy-paste most often in real flows — tested patterns for the date formatting, null handling, HTTP parsing, and subject-line building scenarios that come up in almost every approval or notification flow.
Format a date for emails
When SharePoint returns an ISO timestamp and you need a clean display date:
formatDateTime(triggerOutputs()?['body/Created'], 'MMMM d, yyyy')Output: June 24, 2026. For the US short format: formatDateTime(..., 'M/d/yyyy').
Get file extension from a filename
last(split(triggerOutputs()?['body/{FilenameWithExtension}'], '.'))Splits report-final.pdf on . and returns pdf. Works for any delimiter-based extraction.
Null-safe field access with fallback
coalesce(triggerOutputs()?['body/Manager/Email'], 'no-manager@contoso.com')For numeric fields that might be null:
coalesce(triggerOutputs()?['body/Amount'], 0)Build a dynamic email subject
concat('[', triggerOutputs()?['body/Department'], '] ', triggerOutputs()?['body/RequestType'], ' - ', triggerOutputs()?['body/Title'])Output: [Finance] Purchase Order - Office Supplies Q2
For end-to-end approval flows using this pattern, see the Power Automate document approval workflow guide.
Calculate days between two dates
div(sub(ticks(outputs('EndDate')), ticks(outputs('StartDate'))), 864000000000)Each tick is 100 nanoseconds; 864000000000 ticks = 1 day. For business-days counting (excluding weekends), store holidays in a SharePoint list and subtract them in a loop.
Parse a JSON response from an HTTP action
json(body('HTTP_Request'))?['results']Safe nested access:
coalesce(json(body('HTTP_Request'))?['data']?['value'], 'Not found')For calling external APIs with OAuth from Power Automate flows, see the custom connectors guide.
Build styled HTML for email output
Expressions can build HTML strings inline:
concat('<b>', triggerOutputs()?['body/Title'], '</b><br/>', formatDateTime(triggerOutputs()?['body/DueDate'], 'MMMM d, yyyy'))For applying CSS to HTML tables generated by flows, see Power Automate HTML table styling with CSS.
Practical note: the expression editor in Power Automate (and the underlying WDL engine) shares its function library with Azure Logic Apps. If you find a function in the Logic Apps reference that isn't in the Power Automate UI docs, try it anyway — it usually works. Microsoft keeps the two runtimes in sync but the UI docs sometimes lag by months.
---
Quick Reference: Expression Editor Shortcuts
A few things that trip up new users every time:
- Accessing dynamic content in expressions: Use
triggerOutputs(),outputs('ActionName'), orbody('ActionName')to reference values — never paste raw dynamic content tokens into the expression editor.
- Optional chaining: The
?operator (e.g.,body('Get_item')?['value']) prevents errors when a property doesn't exist.
- Nested quotes: Use single quotes inside expressions. Double quotes break the parser.
- Testing expressions: Use a Compose action — the output shows exactly what the expression returns before you wire it into something consequential.
- Type mismatches: If
equals()returnsfalsewhen you expecttrue, one side is probably a string and the other is an integer. Useint(),float(), orstring()to normalize.
Try functions interactively before adding them to your flow using the Power Automate Expressions tool — test any expression against sample data right in the browser. The same expression patterns apply in Power Apps canvas formulas, too — see the Power Apps canvas app + SharePoint guide for side-by-side examples.
---
Common Expression Syntax Errors and Fixes
These are the errors Power Automate throws most often when expression syntax is wrong — with the exact message and what to change.
InvalidTemplate on save
Full error:
InvalidTemplate. Unable to process template language expressions in action '...' inputs at line '...' and column '...': '...'. Please see https://aka.ms/logicexpressions for usage details.Causes and fixes:
| Root cause | Fix |
|---|---|
| Double quotes inside expression | Replace "value" with 'value' |
| Unmatched parentheses | Count opening vs closing parens — add a missing ) |
@{...} wrapper inside the expression editor | Remove the @{ and } — they're for inline interpolation only |
| Referencing an action name with spaces | Wrap in quotes: outputs('My Action') not outputs(My Action) |
ExpressionEvaluationFailed at runtime
Full error:
The execution of template language expression '...' failed: 'The template language function '...' expects its parameter to be a string...Type mismatch. SharePoint list columns return different types depending on the field type. A Number column returns an integer; pass it to a string function and you'll hit this. Fix with string(triggerOutputs()?['body/Count']).
NullValueInArgumentError at runtime
The execution of template language expression 'first(triggerOutputs()?['body/value'])' failed: '...array was null or empty'.The array was empty. Wrap with an empty() guard:
if(empty(triggerOutputs()?['body/value']), 'No items', first(triggerOutputs()?['body/value'])?['Title'])ActionInputsNotFound for dynamic content
This isn't an expression syntax error — it means the action you're referencing in outputs('ActionName') doesn't exist or has been renamed. Check the internal name of the action (visible in the "..." menu of the action → rename) and update the expression.
div() returns 0 unexpectedly
div() is integer division. div(5, 10) returns 0 not 0.5. Convert to float first:
div(float(5), float(10))From real flows: the most common syntax error I see in shared flow templates is action names with special characters —Get itembecomesGet_iteminternally butGet_item_2if it was renamed. Always use the Dynamic Content pane to grab the exact internal name rather than guessing the string to put insideoutputs().
---
FAQ
What is Power Automate expression syntax?
Power Automate expression syntax is the Workflow Definition Language (WDL) formula system shared with Azure Logic Apps (Microsoft Learn, 2026). Expressions use a function-call form — functionName(arguments) — and are entered in the Expression tab of any action field. They let you transform, compare, and compute values at flow runtime rather than relying on static inputs.
What is the difference between concat() and inline @{...} syntax?
concat() is a function you call in the expression editor. @{...} is an interpolation syntax you use directly in text fields (not the expression tab) to embed an expression result mid-string. They produce the same output but live in different places. Use concat() when you need to combine more than two values — it's easier to debug. Use @{...} for simple inline substitutions in text fields like email subjects.
Can you nest expressions inside other expressions?
Yes — this is how most real expressions work. if(empty(triggerOutputs()?['body/Email']), 'N/A', toLower(triggerOutputs()?['body/Email'])) is a nested expression combining if, empty, and toLower. Watch your parentheses — one missing ) causes InvalidTemplate with a line/column pointer that's often off by one.
How do you handle time zones in Power Automate?
All timestamps in Power Automate are stored as UTC internally. Use convertTimeZone(utcNow(), 'UTC', 'Eastern Standard Time', 'hh:mm tt') before displaying dates to users. The full list of supported time zone names is in the Microsoft Learn reference — use the Windows time zone name format (e.g., Eastern Standard Time, not America/New_York).
Why does equals() return false when both values look the same?
Almost always a type mismatch or a case difference. SharePoint columns return typed values — a Yes/No column returns a boolean, not the string "true". Use string() or int() to normalize before comparing, and toLower() when comparing user-entered text. Use a Compose action to inspect both sides individually before debugging the equals() call.
---
What's Next
- Power Automate Document Approval Workflow — end-to-end flow using expressions for dynamic email subjects and conditional routing
- Power Automate HTML Table Styling with CSS — applying expressions to build formatted HTML in flow emails
- Power Platform Custom Connectors REST API Guide — building connectors that consume the JSON outputs your expressions parse
- Microsoft Learn — WDL Functions Reference — the canonical function reference with full parameter specs