Home Services Work About Blog Contact Let's Talk
Blog / Power Automate
Power Automate

Power Automate Expressions: The Complete Reference Guide for 2026

Expression Basics: How Power Automate Evaluates Expressions

Power Automate expressions are written in a language that Microsoft calls the workflow definition language — a function-based expression language (similar in spirit to Excel formulas) that evaluates at runtime inside the flow engine. Expressions are enclosed in @{} when embedded in strings, or prefixed with @ when used as standalone field values. Understanding this distinction prevents one of the most common novice mistakes: wrapping an entire expression in quotes when it should be a bare @expression() call.

Every expression in Power Automate returns one of six data types: string, integer, float, boolean, array, or object. Type mismatch errors — where a function receives a string when it expects an integer, or vice versa — are the leading cause of flow failures in production. The expression editor in Power Automate's designer does not enforce types at edit time, so errors only surface at runtime. Developing a mental model of what type each function accepts and returns is the single most valuable skill for Power Automate developers beyond the basics.

Expressions can be nested arbitrarily deep — the output of one function becomes the input of another. A complex expression like formatDateTime(addDays(utcNow(), 30), 'dd/MM/yyyy') chains three functions: utcNow() returns the current UTC timestamp, addDays() adds 30 days to it, and formatDateTime() converts the result to a readable date string. Mastering this nesting pattern is what separates Power Automate developers who can solve complex problems in a single expression from those who need five sequential Compose actions to achieve the same result.

Debugging Tip

Use a Compose action with your expression during development and check the run history output before wiring it into a consequential action. The Compose action shows you exactly what the expression evaluates to — invaluable for diagnosing unexpected outputs.

String Functions: concat, substring, replace, split, trim

String manipulation is the most frequently needed category of Power Automate expressions. Whether you are constructing dynamic SharePoint URLs, formatting display names from first and last name fields, or sanitising user input before storage, string functions are in nearly every production flow.

concat() joins two or more strings. Unlike Excel's CONCATENATE, Power Automate's concat accepts unlimited arguments: concat('Hello ', triggerBody()?['Author'], ' — your submission has been received.'). For more readable multi-part strings, consider using the string interpolation syntax inside dynamic content instead: @{triggerBody()?['FirstName']} @{triggerBody()?['LastName']}.

Power Automate — String function reference
// concat — join multiple strings
concat('Project-', variables('ProjectCode'), '-', formatDateTime(utcNow(), 'yyyyMM'))
// Result: "Project-PRJ001-202603"

// substring — extract part of a string
substring('INV-2026-00142', 4, 4)
// Result: "2026"

// replace — swap a substring
replace(triggerBody()?['EmailBody'], '[CompanyName]', 'Contoso Ltd')

// split — convert delimited string to array
split(triggerBody()?['TagList'], ';')
// Input: "finance;legal;hr" → Output: ["finance","legal","hr"]

// trim — remove leading/trailing whitespace
trim(triggerBody()?['SubmittedName'])

// toLower / toUpper
toLower(triggerBody()?['EmailAddress'])

// startsWith / endsWith / contains
startsWith(triggerBody()?['InvoiceNumber'], 'INV')
endsWith(triggerBody()?['FileName'], '.pdf')
contains(triggerBody()?['Description'], 'urgent')

// indexOf — find position of a character
indexOf(triggerBody()?['Email'], '@')

// length — count characters
length(triggerBody()?['Comment'])

Date and Time Functions: utcNow, addDays, formatDateTime, convertTimeZone

Date and time manipulation is the second most common expression need, and also the most error-prone area for developers new to Power Automate. The key mental model to internalise: Power Automate works internally in UTC ISO 8601 format (2026-03-30T09:00:00.0000000Z). All date/time functions that accept a datetime value expect this format. The formatDateTime() function converts to human-readable display; convertTimeZone() shifts to a local timezone.

Power Automate — Date and time function reference
// utcNow — current UTC timestamp
utcNow()
// Result: "2026-03-30T09:00:00.0000000Z"

// formatDateTime — format for display
formatDateTime(utcNow(), 'dd MMMM yyyy')
// Result: "30 March 2026"

formatDateTime(utcNow(), 'yyyy-MM-dd')
// Result: "2026-03-30"

// addDays — add or subtract days
addDays(utcNow(), 30)
addDays(utcNow(), -7)  // 7 days ago

// addHours, addMinutes, addSeconds, addMonths
addHours(utcNow(), 2)
addMonths(utcNow(), 3)

// convertTimeZone — localise for display
convertTimeZone(utcNow(), 'UTC', 'India Standard Time', 'dd/MM/yyyy HH:mm')
// Result: "30/03/2026 14:30"

// dayOfWeek — get day number (0=Sunday)
dayOfWeek(utcNow())

// ticks — compare dates (larger ticks = later date)
greater(ticks(triggerBody()?['DueDate']), ticks(utcNow()))

// getPastTime / getFutureTime
getPastTime(1, 'Month')
getFutureTime(14, 'Day')

Logical Functions: if, and, or, not, equals

Logical functions are the decision-making layer of Power Automate expressions. While the flow designer has dedicated Condition shapes for branching, logical expressions let you inline conditional logic directly inside field values — avoiding extra shapes and making flows more readable. The if() function is the workhorse: if(equals(triggerBody()?['Priority'], 'High'), 'Urgent', 'Normal').

Power Automate — Logical function reference
// if(condition, trueValue, falseValue)
if(equals(triggerBody()?['Status'], 'Approved'), '✓ Approved', '⚠ Pending')

// and / or — combine conditions
and(
  equals(triggerBody()?['Department'], 'Finance'),
  greater(triggerBody()?['Amount'], 10000)
)

or(
  equals(triggerBody()?['Priority'], 'High'),
  equals(triggerBody()?['Priority'], 'Critical')
)

// not — negate a boolean
not(equals(triggerBody()?['IsArchived'], true))

// equals, greater, less, greaterOrEquals, lessOrEquals
greaterOrEquals(triggerBody()?['LeaveBalance'], 5)

// Nested if for multi-branch logic
if(
  equals(triggerBody()?['Score'], 'A'), 'Excellent',
  if(equals(triggerBody()?['Score'], 'B'), 'Good', 'Needs Improvement')
)

// coalesce — return first non-null value
coalesce(triggerBody()?['PreferredName'], triggerBody()?['FirstName'], 'Unknown')

Array Functions: length, first, last, union, intersection, contains, filter

Array functions become essential the moment your flows work with collections — SharePoint list items returned by a "Get items" action, email recipients, multi-select choice values, or JSON arrays from HTTP responses. Mastering array expressions eliminates the need for Apply to Each loops in many common scenarios, dramatically improving flow performance.

Power Automate — Array function reference
// length — count array items
length(outputs('Get_items')?['body/value'])

// first / last — get first or last element
first(outputs('Get_items')?['body/value'])
last(outputs('Get_items')?['body/value'])

// union — combine two arrays (deduplicated)
union(variables('TagsArray1'), variables('TagsArray2'))

// intersection — items present in both arrays
intersection(variables('RequiredRoles'), variables('UserRoles'))

// contains — check if value exists in array
contains(variables('ApprovedCountries'), triggerBody()?['Country'])

// skip / take — slice an array
take(outputs('Get_items')?['body/value'], 5)  // first 5
skip(outputs('Get_items')?['body/value'], 10) // from item 11 onwards

// join — convert array to delimited string
join(variables('TagsArray'), ', ')
// Input: ["finance","legal","hr"] → "finance, legal, hr"

// createArray — build array from values
createArray(
  triggerBody()?['PrimaryEmail'],
  triggerBody()?['CCEmail']
)

// range — generate integer sequence
range(1, 12)  // [1,2,3,...,12]
Performance Note

Use filter() in OData query expressions on SharePoint "Get items" actions rather than filtering with array functions after fetching. Filtering server-side reduces data transferred and speeds up flows significantly — especially on lists with thousands of items.

JSON Functions: json, string, base64, xpath

JSON functions bridge the gap between Power Automate's native data types and raw string payloads. They are essential when integrating with HTTP APIs, parsing webhook bodies, or constructing JSON payloads for outgoing requests.

Power Automate — JSON function reference
// json — parse JSON string into an object
json(triggerBody()?['RawPayload'])

// string — serialise object to JSON string
string(variables('MyObject'))

// base64 — encode string to Base64
base64(concat(variables('ClientId'), ':', variables('ClientSecret')))

// base64ToString — decode Base64
base64ToString(triggerBody()?['EncodedData'])

// decodeUriComponent — decode URL-encoded string
decodeUriComponent(triggerBody()?['CallbackUrl'])

// encodeURIComponent — URL-encode a string
encodeURIComponent(variables('SearchQuery'))

// xpath — extract value from XML
xpath(xml(body('Parse_XML')), 'string(//Invoice/TotalAmount)')

// Construct a JSON object inline
json(
  concat(
    '{"name":"', triggerBody()?['FullName'],
    '","email":"', triggerBody()?['Email'], '"}'
  )
)

Null Handling: Avoiding the ?['field'] vs ['field'] Trap

Null handling is where most Power Automate flows fail silently in production. When a trigger or action output contains a field that may not always be present, accessing it with the standard bracket notation ['FieldName'] throws an error if the field is null or missing. The null-safe operator ?['FieldName'] returns null instead of throwing, allowing your flow to continue and handle the null gracefully.

The correct pattern for null-safe field access is to combine the null-safe operator with coalesce() to provide a default: coalesce(triggerBody()?['OptionalField'], 'Default Value'). This pattern handles three scenarios: the field is present with a value (returns the value), the field is present but null (returns the default), and the field does not exist in the JSON body (returns the default).

Power Automate — Null-safe patterns
// Safe field access with default
coalesce(triggerBody()?['ManagerEmail'], '[email protected]')

// Check for empty string AND null
if(
  or(
    empty(triggerBody()?['Description']),
    equals(triggerBody()?['Description'], null)
  ),
  'No description provided',
  triggerBody()?['Description']
)

// Check before doing math on a nullable number
if(
  equals(triggerBody()?['Quantity'], null),
  0,
  mul(triggerBody()?['Quantity'], triggerBody()?['UnitPrice'])
)

// Null-safe array length (avoids error on null array)
length(coalesce(outputs('Get_items')?['body/value'], createArray()))

20+ Real-World Expression Recipes

The following recipes are drawn from production flows across SharePoint, Teams, Outlook, and custom HTTP integrations. Each solves a concrete problem that appears repeatedly in enterprise Power Automate development.

Power Automate — Production expression recipes
// 1. Extract domain from email address
substring(triggerBody()?['Email'], add(indexOf(triggerBody()?['Email'], '@'), 1), 100)

// 2. Build SharePoint item URL from site and ID
concat(variables('SiteUrl'), '/Lists/Tasks/DispForm.aspx?ID=', triggerBody()?['ID'])

// 3. Get current financial year string (Apr-Mar)
if(
  greaterOrEquals(int(formatDateTime(utcNow(), 'M')), 4),
  concat('FY', formatDateTime(utcNow(), 'yy'), '-', string(add(int(formatDateTime(utcNow(), 'yy')), 1))),
  concat('FY', string(sub(int(formatDateTime(utcNow(), 'yy')), 1)), '-', formatDateTime(utcNow(), 'yy'))
)

// 4. Count business days between two dates (approximate)
sub(
  div(sub(ticks(variables('EndDate')), ticks(variables('StartDate'))), 864000000000),
  mul(div(sub(ticks(variables('EndDate')), ticks(variables('StartDate'))), 6048000000000), 2)
)

// 5. Generate a unique reference number
concat('REF-', formatDateTime(utcNow(), 'yyyyMMdd'), '-',
  substring(guid(), 0, 8))

// 6. Convert array of objects to comma-separated names
join(
  xpath(xml(json(concat('{"r":{"i":', string(variables('PeopleArray')), '}}'))),
    '//i/DisplayName/text()'),
  ', '
)

// 7. Truncate long text for email subject
if(
  greater(length(triggerBody()?['Title']), 60),
  concat(substring(triggerBody()?['Title'], 0, 60), '...'),
  triggerBody()?['Title']
)

// 8. Check if today is a Monday
equals(dayOfWeek(utcNow()), 1)

// 9. Pad a number with leading zeros (e.g., 42 → "00042")
substring(concat('00000', string(triggerBody()?['InvoiceNumber'])),
  sub(length(concat('00000', string(triggerBody()?['InvoiceNumber']))), 5), 5)

// 10. Calculate VAT amount and total
add(
  float(triggerBody()?['NetAmount']),
  mul(float(triggerBody()?['NetAmount']), 0.18)
)

Key Takeaways

Power Automate works internally in UTC ISO 8601 format — always convert timestamps for display with formatDateTime() and convertTimeZone(), never store timezone-converted values.

Use the null-safe operator ?['field'] combined with coalesce() for any field that may be absent or null — this prevents the majority of production flow failures.

Array functions like join(), first(), take(), and skip() often eliminate the need for Apply to Each loops, improving flow performance dramatically.

Prototype complex expressions in a Compose action and verify the output in run history before using them in consequential actions like Send Email or Update Item.

Nested if() expressions handle multi-branch logic inline without adding extra Condition shapes — keep nesting to a maximum of three levels for readability.

AT

Akshara Technologies

Microsoft 365 Development Specialists

With 10+ years building enterprise SharePoint, SPFx, Power Automate, and Flutter solutions for clients across India, USA, UAE, and Australia — we write from production experience, not documentation.

Related Articles

Ready to Automate with Power Automate?

From simple approval flows to complex multi-system automation — Akshara Technologies delivers Power Automate solutions that transform enterprise processes.

Start Your Project View Case Studies