Logic Apps Expressions and Functions
Understanding Expressions
Azure Logic Apps uses the Workflow Definition Language (WDL) for expressions. You can use expressions in action inputs by wrapping them in @{...} for inline use or using @ as a prefix for standalone expressions.
Microsoft Reference: Workflow Definition Language schema
Expression Syntax
| Syntax | Usage | Example |
|---|---|---|
@{expression} |
Inline within a string | "Hello @{triggerBody()?['name']}" |
@expression |
Standalone value | @triggerBody()?['orderId'] |
@{expression1} text @{expression2} |
Multiple inline | "Order @{body('GetOrder')?['id']} for @{body('GetOrder')?['customer']}" |
Accessing Data
| Function | Purpose | Example |
|---|---|---|
triggerBody() |
Get trigger request body | @triggerBody()?['orderId'] |
triggerOutputs() |
Get trigger outputs (including headers) | @triggerOutputs()?['headers']?['X-Request-Id'] |
body('actionName') |
Get action output body | @body('HTTP_Call')?['data'] |
outputs('actionName') |
Get full action outputs | @outputs('HTTP_Call')?['statusCode'] |
actions('actionName') |
Get action status and outputs | @actions('HTTP_Call')?['status'] |
items('For_each') |
Current item in a For Each loop | @items('For_each')?['name'] |
iterationIndexes('For_each') |
Current iteration index | @iterationIndexes('For_each') |
result('Scope') |
Results of all actions in a Scope | @result('Try_Scope') |
variables('varName') |
Get a variable value | @variables('orderCount') |
parameters('paramName') |
Get a workflow parameter | @parameters('apiUrl') |
workflow() |
Workflow metadata | @workflow()?['run']?['name'] |
Microsoft Reference: Expression functions reference
String Functions
| Function | Example | Result |
|---|---|---|
concat() |
concat('Hello', ' ', 'World') |
Hello World |
substring() |
substring('Hello World', 0, 5) |
Hello |
replace() |
replace('Hello World', 'World', 'Azure') |
Hello Azure |
toLower() |
toLower('HELLO') |
hello |
toUpper() |
toUpper('hello') |
HELLO |
trim() |
trim(' hello ') |
hello |
length() |
length('hello') |
5 |
startsWith() |
startsWith('Hello World', 'Hello') |
true |
endsWith() |
endsWith('Hello World', 'World') |
true |
indexOf() |
indexOf('Hello World', 'World') |
6 |
lastIndexOf() |
lastIndexOf('test/path/file', '/') |
9 |
split() |
split('a,b,c', ',') |
["a","b","c"] |
join() |
join(createArray('a','b','c'), ',') |
a,b,c |
guid() |
guid() |
Random GUID string |
nthIndexOf() |
nthIndexOf('a.b.c.d', '.', 2) |
3 |
slice() |
slice('Hello World', 6) |
World |
chunk() |
chunk('abcdef', 2) |
["ab","cd","ef"] |
String Manipulation Examples
// Extract filename from path
@last(split(triggerBody()?['filePath'], '/'))
// Build a reference number
@concat('ORD-', formatDateTime(utcNow(), 'yyyyMMdd'), '-', guid())
// Mask sensitive data (show last 4 characters)
@concat('****', substring(variables('cardNumber'), sub(length(variables('cardNumber')), 4), 4))
// URL encode a value
@encodeUriComponent(triggerBody()?['searchTerm'])
Date and Time Functions
Working with dates is common in Logic Apps:
utcNow() // Current UTC time
utcNow('yyyy-MM-ddTHH:mm:ssZ') // Formatted UTC
addDays(utcNow(), 7) // 7 days from now
addHours(utcNow(), -2) // 2 hours ago
addMinutes(utcNow(), 30) // 30 minutes from now
addSeconds(utcNow(), 0) // Current time (useful for casting)
formatDateTime(utcNow(), 'yyyy-MM-dd') // Date as string
formatDateTime(utcNow(), 'dd/MM/yyyy HH:mm') // UK format
ticks(utcNow()) // Ticks for comparison
convertFromUtc(utcNow(), 'GMT Standard Time') // Convert timezone
convertToUtc('2026-03-14T10:00:00', 'GMT Standard Time') // Convert to UTC
startOfDay(utcNow()) // Start of current day
startOfMonth(utcNow()) // Start of current month
startOfHour(utcNow()) // Start of current hour
dayOfWeek(utcNow()) // 0 (Sunday) to 6 (Saturday)
dayOfMonth(utcNow()) // 1 to 31
dayOfYear(utcNow()) // 1 to 366
Date Comparison Patterns
// Check if a date is in the past
@less(ticks(triggerBody()?['expiryDate']), ticks(utcNow()))
// Calculate age in days
@div(sub(ticks(utcNow()), ticks(triggerBody()?['createdDate'])), 864000000000)
// Check if within business hours (9 AM to 5 PM UK time)
@and(
greaterOrEquals(int(formatDateTime(convertFromUtc(utcNow(), 'GMT Standard Time'), 'HH')), 9),
less(int(formatDateTime(convertFromUtc(utcNow(), 'GMT Standard Time'), 'HH')), 17)
)
Microsoft Reference: Date and time functions
Collection Functions
When working with arrays and objects:
| Function | Description | Example |
|---|---|---|
first() |
First element | first(body('Get_rows')?['value']) |
last() |
Last element | last(split(variables('path'), '/')) |
contains() |
Check existence | contains(triggerBody()?['roles'], 'admin') |
empty() |
Check if null/empty | empty(triggerBody()?['items']) |
length() |
Count elements | length(body('Get_rows')?['value']) |
union() |
Merge arrays | union(variables('list1'), variables('list2')) |
intersection() |
Common elements | intersection(variables('a'), variables('b')) |
skip() |
Skip N elements | skip(variables('items'), 10) |
take() |
Take N elements | take(variables('items'), 5) |
createArray() |
Create an array | createArray('a', 'b', 'c') |
range() |
Number range | range(1, 10) |
sort() |
Sort array | sort(variables('items')) |
reverse() |
Reverse array | reverse(variables('items')) |
Object Functions
| Function | Description | Example |
|---|---|---|
json() |
Parse JSON string | json(body('HTTP')) |
xml() |
Convert to XML | xml(variables('jsonData')) |
xpath() |
Query XML | xpath(xml(body('HTTP')), '//order/id/text()') |
setProperty() |
Set object property | setProperty(body('Get_item'), 'status', 'processed') |
removeProperty() |
Remove property | removeProperty(body('Get_item'), 'internalId') |
addProperty() |
Add property | addProperty(body('Get_item'), 'timestamp', utcNow()) |
Filtering and Transforming Arrays
// Filter with a condition action after For Each
// Use Select (map) action for transformation
// Use Filter Array action for filtering
// Check if any items match
@greater(length(body('Filter_array')), 0)
// Pagination — take page 2 (10 items per page)
@take(skip(body('Get_rows')?['value'], 10), 10)
Conditional Expressions
Use the if() function for conditional logic:
if(equals(triggerBody()?['status'], 'approved'), 'Process', 'Reject')
Comparison Functions
| Function | Description | Example |
|---|---|---|
equals() |
Equality | equals(variables('status'), 'active') |
greater() |
Greater than | greater(variables('count'), 100) |
greaterOrEquals() |
Greater or equal | greaterOrEquals(variables('score'), 80) |
less() |
Less than | less(variables('retries'), 3) |
lessOrEquals() |
Less or equal | lessOrEquals(length(variables('items')), 50) |
and() |
Logical AND | and(equals(a, 1), equals(b, 2)) |
or() |
Logical OR | or(equals(status, 'error'), equals(status, 'failed')) |
not() |
Logical NOT | not(empty(triggerBody()?['email'])) |
Null-Safe Navigation
// The ? operator prevents null reference errors
@triggerBody()?['customer']?['address']?['city']
// Use coalesce for default values
@coalesce(triggerBody()?['priority'], 'normal')
// Multiple fallback values
@coalesce(triggerBody()?['preferredEmail'], triggerBody()?['email'], 'no-email@example.com')
Conversion Functions
| Function | Description | Example |
|---|---|---|
int() |
Convert to integer | int('42') |
float() |
Convert to float | float('3.14') |
string() |
Convert to string | string(42) |
bool() |
Convert to boolean | bool('true') |
array() |
Convert to array | array('hello') |
json() |
Parse JSON string | json('{"key":"value"}') |
xml() |
Convert to XML | xml(variables('jsonString')) |
base64() |
Encode to base64 | base64('Hello') |
base64ToString() |
Decode base64 | base64ToString(body('Get_blob')) |
base64ToBinary() |
Base64 to binary | base64ToBinary(body('Get_file')) |
binary() |
Convert to binary | binary('text content') |
decodeBase64() |
Decode base64 (legacy) | decodeBase64(variables('encoded')) |
encodeUriComponent() |
URL encode | encodeUriComponent('hello world') |
decodeUriComponent() |
URL decode | decodeUriComponent('hello%20world') |
dataUri() |
Convert to data URI | dataUri('text/plain;charset=utf-8') |
uriHost() |
Extract host from URI | uriHost('https://example.com/path') |
uriPath() |
Extract path from URI | uriPath('https://example.com/path') |
uriQuery() |
Extract query string | uriQuery('https://example.com?key=value') |
Math Functions
| Function | Description | Example |
|---|---|---|
add() |
Addition | add(variables('total'), variables('tax')) |
sub() |
Subtraction | sub(variables('balance'), variables('payment')) |
mul() |
Multiplication | mul(variables('quantity'), variables('price')) |
div() |
Division | div(variables('total'), variables('count')) |
mod() |
Modulo | mod(variables('index'), 2) |
min() |
Minimum value | min(variables('a'), variables('b')) |
max() |
Maximum value | max(variables('a'), variables('b')) |
rand() |
Random integer | rand(1, 100) |
Advanced Patterns
Dynamic Property Access
// Access a property dynamically
@body('HTTP')[variables('propertyName')]
// Build dynamic paths
@body('Get_rows')?['value']?[0]?[variables('columnName')]
Working with HTTP Responses
// Get status code
@outputs('HTTP_Call')?['statusCode']
// Get a specific response header
@outputs('HTTP_Call')?['headers']?['Content-Type']
// Check if request was successful
@equals(outputs('HTTP_Call')?['statusCode'], 200)
// Parse response body
@body('HTTP_Call')
// Get the raw body as string
@string(body('HTTP_Call'))
Working with Action Results
// Get status of a previous action
@actions('Send_email')?['status']
// Get all action results within a scope
@result('Try_Scope')
// Filter failed actions
@filter(result('Try_Scope'), item => item['status'] == 'Failed')
// Get the error message from a failed action
@actions('HTTP_Call')?['error']?['message']
Best Practices
- Use
coalesce()to handle null values gracefully — avoids workflow failures on missing data - Prefer
outputs()overbody()for accessing action results when you need headers or status codes - Use
triggerOutputs()headers for HTTP trigger metadata likeContent-Typeor custom headers - Test expressions in the designer using the expression editor's evaluation feature
- Use the
?operator for null-safe property access —triggerBody()?['prop']instead oftriggerBody()['prop'] - Avoid complex nested expressions — use Compose actions to break down complex transformations
- Use
result()in Catch scopes to get detailed error information from Try scopes - Prefer
formatDateTime()over string manipulation when working with dates - Use
createArray()andcreateObject()to construct data structures inline
Tip: The Logic Apps expression editor provides IntelliSense — start typing a function name to see suggestions and parameter hints.