100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Expressions in Flows

Master Power Automate's Workflow Definition Language expressions to transform data, build conditions, and manipulate strings, dates, and arrays.

Triggers & ActionsIntermediate10 min readJul 10, 2026
Analogies

The Expression Language Underneath Every Flow

Every flow in Power Automate compiles down to a JSON document following the Workflow Definition Language (WDL), the same expression syntax used by Azure Logic Apps, and expressions are how you write logic inside that JSON that isn't simply a static value — anything wrapped in @{...} or, for a whole-field expression, prefixed with @ directly, tells the runtime to evaluate a function call rather than treat the text literally. Expressions always start from a small set of accessor functions — triggerOutputs(), triggerBody(), outputs('ActionName'), body('ActionName'), and variables('varName') — and then drill into that JSON using ?['propertyName'] syntax, where the leading ? makes the lookup null-safe instead of throwing an error if the property doesn't exist.

🏏

Cricket analogy: It's like Hawk-Eye's underlying trajectory-prediction algorithm running silently behind every ball-tracking graphic the broadcast shows, with the visible pitch map being just the rendered output of that formula.

String, Date, and Logical Functions

String functions like concat(), substring(), replace(), toUpper(), and trim() manipulate text; date functions like utcNow(), addDays(), formatDateTime(), and convertTimeZone() handle time arithmetic and formatting (using .NET custom format strings such as 'yyyy-MM-dd'); and logical functions like if(), and(), or(), equals(), and empty() drive branching decisions both inside Condition actions and inline within any field. A common real-world pattern combines several: if(equals(triggerOutputs()?['body/Status'], 'Urgent'), concat('URGENT: ', triggerOutputs()?['body/Subject']), triggerOutputs()?['body/Subject']) builds a subject line that prefixes 'URGENT:' only when the status field matches, entirely inline without needing a separate Condition action.

🏏

Cricket analogy: It's like a broadcast graphics template that concatenates a batter's name with their milestone ('Kohli - CENTURY') only if their score equals or exceeds 100, otherwise showing just the plain score, all computed inline by the graphics engine.

A Compose Expression Example

text
if(
  equals(triggerOutputs()?['body/Status'], 'Urgent'),
  concat('URGENT: ', triggerOutputs()?['body/Subject']),
  triggerOutputs()?['body/Subject']
)

// Formatting a date for a report filename
concat('Report_', formatDateTime(utcNow(), 'yyyy-MM-dd'), '.csv')

// Null-safe property access with a default
coalesce(triggerOutputs()?['body/ManagerEmail'], 'default@contoso.com')

coalesce() is one of the most underused expressions: it returns the first non-null argument from a list, making it ideal for supplying fallback values when an optional SharePoint or Dataverse field might be empty, avoiding a separate Condition action just to check for blanks.

Array and Collection Expressions

Array functions such as length(), first(), last(), filter(), and select() let you work with entire collections without writing an explicit Apply to each loop in many cases: filter(body('Get_items')?['value'], item() => equals(item()?['Status']?['Value'], 'Approved')) returns only the approved items from a larger array, and select(body('Get_items')?['value'], item() => item()?['Title']) projects out just the title from every item into a new flat array, both of which can feed directly into a 'Create CSV table' or 'Send an email' action without any loop actions at all, reducing both flow complexity and the number of billed actions.

🏏

Cricket analogy: filter() is like a stats query that pulls only the deliveries from an over that were dot balls, discarding every scoring shot, producing a filtered subset without re-watching the whole over ball by ball.

filter() and select() use an inline lambda parameter (commonly named item()) that only exists within that expression; you cannot reference item() outside the filter/select call, and nesting a filter() inside a select() (or vice versa) requires renaming the lambda parameter in the outer function to avoid ambiguous references — Power Automate's designer will flag this as a parsing error if both use the default 'item'.

  • Every flow compiles to Workflow Definition Language (WDL) JSON, and expressions are how you write logic inline in that JSON.
  • Core accessor functions are triggerOutputs(), triggerBody(), outputs(), body(), and variables(), drilled into with null-safe ?[...] syntax.
  • String, date, and logical functions (concat, formatDateTime, if, equals) can be combined inline without a separate Condition action.
  • coalesce() returns the first non-null value in a list, useful for default values on optional fields.
  • Array functions filter() and select() let you query and project collections without an explicit Apply to each loop.
  • Using filter/select instead of loops reduces flow complexity and the number of billed actions.
  • Lambda parameters inside filter()/select() (e.g., item()) must be renamed when nesting to avoid ambiguous references.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#PowerAutomateStudyNotes#ExpressionsInFlows#Expressions#Flows#Expression#Language#StudyNotes#SkillVeris#ExamPrep