A maker builds a flow on Monday that emails the sales manager when a high-value opportunity moves to the negotiation stage. By Friday, three more makers have built three more flows that do almost the same thing in slightly different ways, none of them following the same naming convention. Power Automate is fast to build with and slow to govern. The patterns below are the ones that hold up past the first month.
Trigger Types
Dataverse: when row added, updated, deleted, scheduled, manual (button or Flow Launch Panel). Pick the narrowest trigger — row-filtered triggers fire less often. The single biggest performance lever in any flow is the trigger filter expression; without it, the flow fires on every row change in the table and discards 99 percent of executions.
trigger: When a row is updated
table: opportunity
scope: Organization
filter: estimatedvalue gt 100000 and statecode eq 0
The filter expression runs server-side before the flow is dispatched. A flow without a filter on a high-volume table eats your daily run quota in days.
Actions and Connectors
Dataverse actions for D365 CRUD. 1,000 plus connectors for external systems. Approvals, Teams notifications, email — all one-click. Use the Dataverse connector for read and write operations rather than the older Common Data Service connector; the Dataverse connector supports better filtering and is faster on large tables.
Best practice action ordering:
1. Trigger with narrow filter
2. Initialize variables for shared values
3. Get related records once, reuse
4. Apply business logic in scope blocks
5. Write to Dataverse with explicit error handling
Error Handling
Each action can have run after set to failure. Build explicit failure paths — notify admin, log to SharePoint, retry. Without error handling, a silent failure is the worst outcome. The pattern that scales is a single Try-Catch-Finally scope structure that every flow follows.
Try scope: business logic
Catch scope (run after Try fails or times out): log error to a Dataverse error table, post to a Teams ops channel
Finally scope (run after both): increment run counter
Standardize this shape and any flow author can debug any other flow’s failure.
Child Flows
Extract reusable logic into child flows. Parent calls child with parameters. Avoids the copy-paste flow sprawl that plagues many orgs. Child flows live in solutions and version with the parent solution; an unsolutioned child flow cannot be called by a solutioned parent.
Child flow signature:
Inputs: AccountId (Text), NotificationType (Text)
Outputs: Status (Text), Message (Text)
The discipline is to define the input and output contract before writing the body. Without it, child flows mutate over time and break callers silently.
Monitoring
Flow Analytics shows runs, failures, durations. Monitor weekly. A flow that fails silently for a month is a real-world pattern. The 28-day analytics window is short; pipe the run data to a Dataverse table for longer retention if you need quarterly trend analysis.
async function logFlowRun(flowId, runId, status, duration) {
await fetch("/api/data/v9.2/cr_flowruns", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ cr_flowid: flowId, cr_runid: runId, cr_status: status, cr_duration: duration })
});
}
Naming and Solution Hygiene
Adopt a naming convention and put it in your maker onboarding doc. The shape that works is Object_Trigger_Action_Owner. Sales_OppUpdate_NotifyManager_Marketing. Without the convention, finding the flow that sends a particular email becomes a half-day investigation.
Naming examples:
Sales_OppCreate_AssignOwner_SalesOps
Service_CaseUpdate_EscalateSLABreach_ServiceOps
Marketing_LeadCreate_RouteByGeo_MarketingOps
Connection Reference Hygiene
Every flow uses connections. In a solution, connections become connection references that the deployer maps per environment. Without connection references, a flow exported from dev points to dev connections in production and silently fails. Convert every flow to use connection references before solution export.
What to do this week
Audit your flows for trigger filters, run-after error paths, and naming convention compliance. Stand up the Try-Catch-Finally template and require it on new flows. Convert all production flows to use connection references and document the mapping for each environment.