15 Power Automate Expressions Every Maker Should Memorize
Most slow Power Automate builds are not slow because the maker is careless. They are slow because every small transformation becomes another action, another run-history click, and another place for nulls to break the flow. Memorizing a compact set of Workflow Definition Language expressions lets you design with intent instead of hunting through dynamic content.
Null handling deserves muscle memory
Start with safe defaults. coalesce is the expression I use most in production flows because connector responses are inconsistent. Dataverse might return a missing alternate phone number, SharePoint might return an empty person field, and an HTTP response might omit an optional property. coalesce gives the first non-null value, which is different from checking only for an empty string.
Use if when the branch is simple. If the decision spans multiple actions, use conditions. If the decision returns one value, keep it inside the expression. Combine that with equals, and, and or when the rule is readable in one line.
coalesce(triggerBody()?['email'], triggerBody()?['upn'], 'unknown@example.com')
if(empty(triggerBody()?['phone']), 'No phone supplied', triggerBody()?['phone'])
equals(toLower(triggerBody()?['status']), 'approved')
and(equals(triggerBody()?['status'], 'Approved'), not(empty(triggerBody()?['approver'])))
or(equals(triggerBody()?['priority'], 'High'), equals(triggerBody()?['vip'], true))
Dates are cleaner when you stop composing strings
Treat time as data, not text. utcNow gives you the current timestamp. formatDateTime turns dates into the shape the target system expects. addDays and addHours are the practical workhorses for service-level agreements, reminders, and expiry logic.
Use ticks for date math. When you need duration, convert two timestamps to ticks and subtract. One second is ten million ticks, so you can calculate hours or days without building fragile string comparisons.
utcNow()
formatDateTime(utcNow(), 'yyyy-MM-dd')
addDays(utcNow(), 7, 'yyyy-MM-ddTHH:mm:ssZ')
addHours(triggerBody()?['submittedOn'], 48)
div(sub(ticks(utcNow()), ticks(triggerBody()?['createdOn'])), 864000000000)
Arrays become predictable with a small toolkit
Check before you index. length tells you how many items you have. empty is the readable guard for arrays, strings, and objects. Use first and last only after you know the array is not empty, or wrap the access with a safe fallback.
Know your loop context. Inside Apply to each, item points at the current element. items points at a named loop. Use items when nested loops make item ambiguous. This one habit prevents a surprising number of wrong-record updates.
length(body('List_rows')?['value'])
empty(body('Filter_array'))
first(body('List_rows')?['value'])?['accountid']
last(outputs('Compose_OrderLines'))?['sku']
item()?['name']
items('Apply_to_each_contact')?['emailaddress1']
Action outputs are contracts you should read directly
Use outputs when you need the whole action result. It includes headers, status code, and body for many actions. Use body when you want the payload only. Both are more stable than repeatedly selecting dynamic content tokens after a rename.
Convert intentionally. json parses text into an object or array. string serializes a value for logging, comparison, or transport. Avoid bouncing values between string and object forms unless you have a reason.
outputs('HTTP')?['statusCode']
body('HTTP')?['value']
json(outputs('Compose_RawPayload'))?['customer']?['name']
string(body('Get_a_row_by_ID')?['revenue'])
Text shaping is usually one expression away
Use simple transformations close to the source. replace cleans known characters. split turns delimited text into an array. join turns an array into a readable string. createArray is useful when a later action demands an array even though you only have one or two known values.
replace(triggerBody()?['phone'], ' ', '')
split(triggerBody()?['tags'], ',')
join(body('Select_EmailAddresses'), ';')
createArray(triggerBody()?['primaryEmail'], triggerBody()?['secondaryEmail'])
variables('retryCount')
A quick reference keeps reviews focused
Use this table during design reviews. It is not a syntax encyclopedia. It is the shortlist that catches the most production bugs and removes the most unnecessary actions.
| Expression | Use it for | Production note |
|---|---|---|
coalesce | Fallback values | Handles null, not every blank string scenario |
if | Inline branching | Keep it short or use a Condition |
equals, and, or | Boolean rules | Normalize case before comparing user text |
formatDateTime | Date display and API formats | Always specify the format |
addDays, addHours | Deadlines and windows | Be clear about UTC versus local expectations |
utcNow | Current timestamp | Prefer it over local time in automation |
ticks | Duration math | Convert results into days or hours explicitly |
length, empty | Guards | Check arrays before using first |
first, last | Boundary records | Safe only when the array has data |
item, items | Loop records | Use named items in nested loops |
outputs, body | Action results | outputs is broader, body is cleaner |
json, string | Type conversion | Convert once at the boundary |
replace, split, join | Text cleanup | Prefer Select for object reshaping |
createArray | Small arrays | Useful for consistent downstream schemas |
variables | Shared state | Avoid variables inside concurrent loops |
The best expressions remove actions, not readability
The goal is leverage. A flow with five expressive Compose actions is better than a flow with twenty vague data operations. But a single monster expression is not senior engineering. The senior move is to put stable shaping in expressions, keep business decisions visible, and name every action as if the next person will debug it at 2 AM.
Name the intermediate steps when the expression becomes a contract. I still use Compose actions for important boundaries: normalized email, calculated due date, selected customer payload, or parsed API response. That gives you a stable token to reuse and a run-history checkpoint that explains the data shape. Expressions should remove accidental complexity, not erase evidence.
Memorize these expressions until they feel boring. Boring expressions are how you make Power Automate runs shorter, safer, and easier to explain when the business asks why one record took a different path.
Keep reading
Calling the Dataverse Web API from Power Automate with the HTTP Action
Learn when to call the Dataverse Web API from Power Automate for actions, functions, batch requests, impersonation, row association, and binds.
Child Flows in Power Automate: Reuse, Pass Data, and Avoid Duplication
Use child flows in Power Automate to centralize reusable logic, pass typed inputs and outputs, handle errors, reduce duplication, and improve ALM.
Speeding Up Apply to Each: Concurrency, Filters, and Select in Power Automate
Speed up Power Automate Apply to each loops with concurrency, Filter array, Select, OData filters, pagination strategy, lower action counts, and safer runs.
Newsletter
New posts, straight to your inbox
One email per post. No spam, no tracking pixels, unsubscribe anytime.
Comments
No comments yet. Be the first.