<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alex Pechenizkiy</title>
    <description>The latest articles on DEV Community by Alex Pechenizkiy (@az365ai).</description>
    <link>https://dev.to/az365ai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3969141%2Fb5e3e816-d15e-43d1-9916-2fbc9eed6fd3.jpg</url>
      <title>DEV Community: Alex Pechenizkiy</title>
      <link>https://dev.to/az365ai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/az365ai"/>
    <language>en</language>
    <item>
      <title>Power Automate Naming Conventions That Scale</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Mon, 21 Sep 2026 18:59:46 +0000</pubDate>
      <link>https://dev.to/az365ai/power-automate-naming-conventions-that-scale-453d</link>
      <guid>https://dev.to/az365ai/power-automate-naming-conventions-that-scale-453d</guid>
      <description>&lt;p&gt;Open the Power Platform Admin Center. Navigate to your production environment. Click into the flow list. What do you see?&lt;/p&gt;

&lt;p&gt;"My Flow." "Test - Copy." "John's Approval Flow (2)." "Untitled." Fourteen flows named "When an item is created."&lt;/p&gt;

&lt;p&gt;This is the reality of most Power Automate tenants. And it's not a minor inconvenience. When something breaks at 2 AM, you need to find the right flow in seconds. When a maker leaves the organization, someone else needs to understand what each flow does. When you run an inventory across 300 flows, naming is the difference between actionable data and noise.&lt;/p&gt;

&lt;p&gt;Naming conventions are the cheapest governance control you can implement. No licenses required. No premium features. Just discipline and a standard that everyone follows.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use a four-segment naming pattern for every Power Automate flow: Domain-Entity-Action-Trigger. Apply the same discipline to connection references and environment variables. This single standard makes flow inventories searchable, troubleshooting faster, and governance automatable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fnaming-conventions-hero.svg%3Fv%3D5a8286fe" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fnaming-conventions-hero.svg%3Fv%3D5a8286fe" alt="Before and after comparison of messy flow names versus structured naming conventions" width="756" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Naming Pattern
&lt;/h2&gt;

&lt;p&gt;Every cloud flow name should follow this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{Domain}-{Entity}-{Action}-{Trigger}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four segments, hyphen-separated, no spaces. Each segment serves a specific purpose.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain Codes
&lt;/h3&gt;

&lt;p&gt;The domain identifies which business area owns the flow. Use short, uppercase codes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Domain&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HR&lt;/td&gt;
&lt;td&gt;Human Resources&lt;/td&gt;
&lt;td&gt;Onboarding, evaluations, leave requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FIN&lt;/td&gt;
&lt;td&gt;Finance&lt;/td&gt;
&lt;td&gt;Invoices, expenses, budget approvals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SALES&lt;/td&gt;
&lt;td&gt;Sales&lt;/td&gt;
&lt;td&gt;Leads, opportunities, quotes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IT&lt;/td&gt;
&lt;td&gt;Information Technology&lt;/td&gt;
&lt;td&gt;Provisioning, tickets, access requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OPS&lt;/td&gt;
&lt;td&gt;Operations&lt;/td&gt;
&lt;td&gt;Work orders, scheduling, logistics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MKT&lt;/td&gt;
&lt;td&gt;Marketing&lt;/td&gt;
&lt;td&gt;Campaigns, events, content approvals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PROC&lt;/td&gt;
&lt;td&gt;Procurement&lt;/td&gt;
&lt;td&gt;Purchase orders, vendor management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEC&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;Access reviews, compliance checks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your organization has specific departments that don't fit these codes, create your own. The key is consistency. Pick a list, publish it, and enforce it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entity
&lt;/h3&gt;

&lt;p&gt;The entity is what the flow operates on. Use the business object name, not the Dataverse table name. "Evaluation" not "cr4b2_evaluation." "Invoice" not "salesinvoice." Keep it readable by a business user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Action
&lt;/h3&gt;

&lt;p&gt;The action describes what the flow does. Common actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Create&lt;/strong&gt; - creates a record or resource&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notify&lt;/strong&gt; - sends a notification (email, Teams, push)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sync&lt;/strong&gt; - synchronizes data between systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approve&lt;/strong&gt; - routes through an approval process&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Archive&lt;/strong&gt; - moves or flags records for archival&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate&lt;/strong&gt; - checks data against business rules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calculate&lt;/strong&gt; - computes values (totals, scores, dates)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export&lt;/strong&gt; - generates files or reports&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Trigger
&lt;/h3&gt;

&lt;p&gt;The trigger tells you what starts the flow. This is critical for troubleshooting. If you know a flow fires on record creation and the issue started after someone bulk-imported records, you have your answer.&lt;/p&gt;

&lt;p&gt;Common trigger suffixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OnCreate&lt;/strong&gt; - when a record is created&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OnUpdate&lt;/strong&gt; - when a record is modified&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OnStatusChange&lt;/strong&gt; - when a status field changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled&lt;/strong&gt; - runs on a timer (daily, weekly, hourly)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual&lt;/strong&gt; - triggered by a button or user action&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OnEmail&lt;/strong&gt; - triggered by an incoming email&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OnApproval&lt;/strong&gt; - triggered by an approval response&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real Examples
&lt;/h2&gt;

&lt;p&gt;Here's what good naming looks like in practice:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bad Name&lt;/th&gt;
&lt;th&gt;Good Name&lt;/th&gt;
&lt;th&gt;Why It's Better&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Send notification&lt;/td&gt;
&lt;td&gt;HR-Evaluation-SubmitNotification-OnStatusChange&lt;/td&gt;
&lt;td&gt;You know the domain, what it acts on, what it does, and what triggers it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invoice approval&lt;/td&gt;
&lt;td&gt;FIN-Invoice-ApprovalRequest-OnCreate&lt;/td&gt;
&lt;td&gt;Distinguishes from the 4 other invoice flows in the environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sync contacts&lt;/td&gt;
&lt;td&gt;SALES-Contact-SyncToCRM-Scheduled&lt;/td&gt;
&lt;td&gt;Clear that it's a scheduled sync, not a real-time trigger&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;My Flow (2)&lt;/td&gt;
&lt;td&gt;IT-AccessRequest-Provision-OnApproval&lt;/td&gt;
&lt;td&gt;Self-documenting. No guessing required.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weekly report&lt;/td&gt;
&lt;td&gt;MKT-Campaign-ExportMetrics-Scheduled&lt;/td&gt;
&lt;td&gt;Tells you exactly which report and when it runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Untitled&lt;/td&gt;
&lt;td&gt;PROC-PurchaseOrder-Validate-OnCreate&lt;/td&gt;
&lt;td&gt;The flow name IS the documentation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When you have 50 flows in an environment, these names let you filter by domain, sort alphabetically, and find exactly what you need. When you have 200 flows, this naming convention is the only thing standing between you and chaos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connection Reference Naming
&lt;/h2&gt;

&lt;p&gt;Connection references are the mechanism that lets you deploy solutions across environments without hardcoding credentials. They get their own naming convention:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{publisher}_{connector}_{purpose}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All lowercase, underscores as separators.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bad Name&lt;/th&gt;
&lt;th&gt;Good Name&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SharePoint Connection&lt;/td&gt;
&lt;td&gt;contoso_sharepointonline_hrdocuments&lt;/td&gt;
&lt;td&gt;Specifies which SharePoint connection for what purpose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Outlook&lt;/td&gt;
&lt;td&gt;contoso_office365outlook_notifications&lt;/td&gt;
&lt;td&gt;Distinguishes from the Outlook connection used for approvals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dataverse&lt;/td&gt;
&lt;td&gt;contoso_dataverse_hrsystem&lt;/td&gt;
&lt;td&gt;When you have 3 Dataverse connections for different solutions, this matters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;My SQL Connection&lt;/td&gt;
&lt;td&gt;contoso_sql_financereporting&lt;/td&gt;
&lt;td&gt;Identifies the target system and purpose&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Why does the publisher prefix matter? Because when you import a managed solution, the connection references show up in the target environment. If two different ISVs both have a connection reference called "SharePoint," you have a collision. The publisher prefix prevents that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Variable Naming
&lt;/h2&gt;

&lt;p&gt;Environment variables store configuration values that change between environments. URLs, email addresses, feature flags, thresholds. Same idea:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{publisher}_{Domain}_{VariableName}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;contoso_HR_NotificationMailbox&lt;/code&gt; - the email address that receives HR notifications&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contoso_FIN_ApprovalThreshold&lt;/code&gt; - the dollar amount that triggers executive approval&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contoso_IT_ServiceNowBaseUrl&lt;/code&gt; - the ServiceNow instance URL for the IT integration&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contoso_SALES_LeadScoringEnabled&lt;/code&gt; - feature flag for the lead scoring flow&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Building Power Platform governance?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This naming standard is one piece of a complete governance framework. For more patterns on environment strategy, solution awareness, and flow inventory, &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;follow Alex on LinkedIn&lt;/a&gt; where I share practical Power Platform architecture posts every week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use consistent naming across all three&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When your flow is named &lt;code&gt;HR-Evaluation-SubmitNotification-OnStatusChange&lt;/code&gt;, its connection reference is &lt;code&gt;contoso_office365outlook_hrnotifications&lt;/code&gt;, and its environment variable is &lt;code&gt;contoso_HR_NotificationMailbox&lt;/code&gt;, an admin can trace the entire chain without opening anything. The naming convention IS the documentation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Flow Description Template
&lt;/h2&gt;

&lt;p&gt;The flow name tells you what. The description tells you why and how. Every flow should have a description that follows this template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Purpose: [One sentence explaining the business reason]
Owner: [Team or role, not a person's name]
Dependencies: [External systems, other flows, specific data]
SLA: [Expected run time and any time-sensitive requirements]
Last reviewed: [Date of last review]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Purpose: Sends email notification to the evaluation manager when
an employee submits their self-evaluation for review.
Owner: HR Operations Team
Dependencies: Office 365 Outlook connector, Evaluation table,
contoso_HR_NotificationMailbox environment variable
SLA: Must complete within 5 minutes of status change
Last reviewed: 2026-03-01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes 30 seconds to write. It saves hours when someone is troubleshooting at 11 PM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforcement
&lt;/h2&gt;

&lt;p&gt;A naming convention that nobody follows is just a document. Here's how you actually enforce it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Publish the standard&lt;/strong&gt; Write it down. Put it in your governance wiki, your CoE documentation, your maker onboarding materials. Make it findable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add it to your maker welcome content&lt;/strong&gt; Managed Environments let you configure a welcome message for makers. Include a link to the naming standard. Every maker sees it when they open the environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a compliance check flow&lt;/strong&gt; Use the Power Automate Management connector or PowerShell (Get-AdminFlow) to pull all flow names. Run a regex against the naming pattern. Flag violations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the CoE Starter Kit&lt;/strong&gt; The Center of Excellence Starter Kit includes inventory flows that sync all flows to Dataverse. Build a model-driven app or Power BI report that highlights flows not matching the pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review in your governance cadence&lt;/strong&gt; Monthly or quarterly, review the compliance report. Reach out to makers with non-compliant flows. Rename or ask them to rename. This is a conversation, not a punishment.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Don't block flow creation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some admins want to prevent flows from being saved unless the name matches a pattern. Power Platform doesn't support this natively, and custom enforcement that blocks makers will kill adoption. Use detection and coaching, not blocking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Regex Pattern
&lt;/h2&gt;

&lt;p&gt;If you want to validate flow names programmatically, here's a regex pattern that matches the convention:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;^[A-Z]{2,5}-[A-Za-z]+-[A-Za-z]+-(?:OnCreate|OnUpdate|OnStatusChange|Scheduled|Manual|OnEmail|OnApproval)$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2-5 uppercase letters for the domain&lt;/li&gt;
&lt;li&gt;One or more letters for the entity&lt;/li&gt;
&lt;li&gt;One or more letters for the action&lt;/li&gt;
&lt;li&gt;A known trigger suffix&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can expand the trigger list as needed. The point is that the check is automatable.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Name Child Flows and Desktop Flows?
&lt;/h2&gt;

&lt;p&gt;Child flows and desktop flows follow the same four-segment naming convention with one addition. Child flows append a &lt;code&gt;_Child&lt;/code&gt; suffix so you can instantly distinguish them in an inventory. Desktop flows replace the trigger segment with &lt;code&gt;Desktop&lt;/code&gt;, making it clear which runtime executes them. Both approaches keep your naming consistent across flow types.&lt;/p&gt;

&lt;p&gt;Child flows (flows called by other flows) follow the same convention but add a &lt;code&gt;_Child&lt;/code&gt; suffix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HR-Evaluation-SendEmail-OnCreate_Child
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Desktop flows use a similar pattern but replace the trigger segment with &lt;code&gt;Desktop&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FIN-Invoice-ExtractLineItems-Desktop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes it immediately obvious in an inventory which flows are cloud flows, which are child flows, and which are desktop flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Today
&lt;/h2&gt;

&lt;p&gt;You don't need to rename every flow in your tenant on day one. Start with new flows. Apply the standard going forward. Then work through the backlog in batches, prioritizing production environments and business-critical flows.&lt;/p&gt;

&lt;p&gt;The naming convention is the foundation for everything else in this series. Environment strategy, solution awareness, and flow inventory all become dramatically easier when every flow has a name that tells you exactly what it is.&lt;/p&gt;




&lt;h2&gt;
  
  
  Power Automate Governance - The Enterprise Playbook
&lt;/h2&gt;

&lt;p&gt;This article is part of a 10-part series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale/" rel="noopener noreferrer"&gt;Naming Conventions That Scale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;Environment Strategy - Dev Test Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm/" rel="noopener noreferrer"&gt;Solution-Aware Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see/" rel="noopener noreferrer"&gt;Flow Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-pipelines-moving-flows-from-dev-to-prod/" rel="noopener noreferrer"&gt;Pipelines - Dev to Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/coe-starter-kit-what-it-does-and-what-to-build-on-top/" rel="noopener noreferrer"&gt;CoE Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production/" rel="noopener noreferrer"&gt;AI-Powered Flow Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track/" rel="noopener noreferrer"&gt;Versioning and Source Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory/" rel="noopener noreferrer"&gt;The Governance Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-weekly-governance-digest-automated-health-report/" rel="noopener noreferrer"&gt;Weekly Governance Digest&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>governance</category>
    </item>
    <item>
      <title>Power Automate Environment Strategy - Dev Test Prod Done Right</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Sun, 20 Sep 2026 17:12:19 +0000</pubDate>
      <link>https://dev.to/az365ai/power-automate-environment-strategy-dev-test-prod-done-right-39hl</link>
      <guid>https://dev.to/az365ai/power-automate-environment-strategy-dev-test-prod-done-right-39hl</guid>
      <description>&lt;p&gt;Open the Power Platform Admin Center. Click on Environments. If you see one environment where every Power Automate flow runs - the default - this article is for you.&lt;/p&gt;

&lt;p&gt;The default environment is the single biggest governance liability in Power Platform. Every licensed user in your tenant gets the Environment Maker role in the default environment. Every user can create flows, apps, and connections there. Every user's work sits next to every other user's work. There are no guardrails, no separation, and no way to promote tested work to production because there's only one environment. Everything is production.&lt;/p&gt;

&lt;p&gt;This is how most organizations run Power Automate. And it works until it doesn't. Until someone's test flow sends 10,000 emails to real customers. Until a maker's experimental flow consumes all the API capacity. Until you need to roll back a change and realize there's nothing to roll back to because there's no dev/test/prod separation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every Power Automate workload needs at least three environments: dev, test, and production. Use developer environments for maker sandboxes, environment routing to keep the default environment clean, and Managed Environments for governance controls.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fenvironment-strategy-hero.svg%3Fv%3D903e8ebd" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fenvironment-strategy-hero.svg%3Fv%3D903e8ebd" alt="Three-environment pipeline showing Dev Test and Prod with quality gates between stages" width="844" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The 3-Environment Minimum
&lt;/h2&gt;

&lt;p&gt;At minimum, you need three environments for any workload that matters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Who Has Access&lt;/th&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Development&lt;/td&gt;
&lt;td&gt;Build and iterate on flows&lt;/td&gt;
&lt;td&gt;Makers and developers&lt;/td&gt;
&lt;td&gt;Sample/test data only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test (UAT)&lt;/td&gt;
&lt;td&gt;Validate before production&lt;/td&gt;
&lt;td&gt;Makers, testers, business stakeholders&lt;/td&gt;
&lt;td&gt;Production-like data (anonymized if needed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production&lt;/td&gt;
&lt;td&gt;Live business processes&lt;/td&gt;
&lt;td&gt;End users via apps, flows run automatically&lt;/td&gt;
&lt;td&gt;Real business data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This isn't new. Software development has followed dev/test/prod for decades. Power Platform is software development. The fact that citizen developers build flows doesn't change the fundamental need for environment separation.&lt;/p&gt;

&lt;p&gt;Solutions move from Dev to Test to Prod through managed solution exports and imports. Connection references and environment variables handle the configuration differences between environments. This is Application Lifecycle Management (ALM), and it's the only way to reliably deploy Power Automate flows at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Environments
&lt;/h2&gt;

&lt;p&gt;Developer environments solve a specific problem: makers need a place to experiment without polluting shared environments. In the past, organizations either gave makers access to the default environment (too risky) or created shared dev environments (still messy).&lt;/p&gt;

&lt;p&gt;Developer environments are personal sandboxes. Key facts from Microsoft's current documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each user can create up to &lt;strong&gt;3 developer environments&lt;/strong&gt; through the Power Platform admin center&lt;/li&gt;
&lt;li&gt;They include &lt;strong&gt;Dataverse&lt;/strong&gt; at no additional storage cost to the tenant&lt;/li&gt;
&lt;li&gt;Capacity: &lt;strong&gt;2 GB database&lt;/strong&gt;, &lt;strong&gt;750 flow runs per month&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;They are meant for development and testing, &lt;strong&gt;not production use&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-cleanup&lt;/strong&gt;: disabled after 30 days of inactivity, then deleted 15 days later if not re-enabled&lt;/li&gt;
&lt;li&gt;The Developer Plan license is free and gives access to premium connectors for dev/test purposes&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Developer environments are not trial environments&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Trial environments expire after 30 days. Developer environments persist as long as there's activity. They're cleaned up only when inactive. Different mechanism, different purpose.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Default Environment Routing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fenvironment-routing-flow.svg%3Fv%3D4056a28f" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fenvironment-routing-flow.svg%3Fv%3D4056a28f" alt="Flow diagram showing environment routing redirecting makers to personal developer environments instead of the default environment" width="1200" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the governance feature that ties it together. Environment routing automatically redirects makers away from the default environment and into their own personal developer environments.&lt;/p&gt;

&lt;p&gt;When enabled, a maker who navigates to make.powerapps.com or make.powerautomate.com lands in their own developer environment instead of the default. If they don't have a developer environment yet, one's created automatically.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open Power Platform admin center&lt;/strong&gt; Navigate to admin.powerplatform.microsoft.com. You need Power Platform admin privileges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go to Manage &amp;gt; Tenant settings &amp;gt; Environment routing&lt;/strong&gt; Find the Environment routing setting under Tenant settings. It's off by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select the product portals&lt;/strong&gt; Choose which portals trigger routing: Power Apps, Power Automate, Copilot Studio. Enable all three for full coverage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a new routing rule&lt;/strong&gt; Select New rule. Give it a name. Choose whether to route Everyone or a specific security group.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assign an environment group&lt;/strong&gt; Select the environment group that new developer environments will be automatically placed into. This ensures group-level governance rules apply immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save and test&lt;/strong&gt; Save the rule. Have a test user navigate to make.powerautomate.com. They should land in their developer environment, not the default.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The developer environments created by routing are &lt;strong&gt;Managed Environments by default&lt;/strong&gt;. This means they inherit the preconfigured settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sharing limits&lt;/strong&gt;: excludes sharing with security groups, limited to 5 individuals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution Checker&lt;/strong&gt;: set to Warn&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usage insights&lt;/strong&gt;: enabled&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Premium license requirement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A premium license isn't required to create or preview resources in a managed developer environment. But users need a premium license to run resources there. The Developer Plan covers creation and testing. Running in production requires a paid license.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Do Managed Environments Actually Add?
&lt;/h2&gt;

&lt;p&gt;Managed Environments give admins sharing limits, solution checker enforcement, usage insights, maker welcome content, and environment-level data policies. They layer governance controls on top of any existing environment without changing how makers build. The tradeoff is that users who run resources in a Managed Environment need premium licensing.&lt;/p&gt;

&lt;p&gt;Managed Environments are not a separate environment type. They're a set of capabilities you enable on an existing environment.&lt;/p&gt;

&lt;p&gt;What Managed Environments add:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Without Managed Environments&lt;/th&gt;
&lt;th&gt;With Managed Environments&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sharing limits&lt;/td&gt;
&lt;td&gt;Anyone can share with anyone&lt;/td&gt;
&lt;td&gt;Admins control sharing limits per environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solution Checker enforcement&lt;/td&gt;
&lt;td&gt;Optional, maker's choice&lt;/td&gt;
&lt;td&gt;Enforced at environment level (None, Warn, or Block)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Usage insights&lt;/td&gt;
&lt;td&gt;Limited to admin center analytics&lt;/td&gt;
&lt;td&gt;Richer usage data in the admin center&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maker welcome content&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Custom welcome message with links to governance docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data policies&lt;/td&gt;
&lt;td&gt;Tenant-level DLP only&lt;/td&gt;
&lt;td&gt;Environment-level DLP enforcement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backup and restore&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;Enhanced with longer retention&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Managed Environments require premium licensing for users who run resources. This is the tradeoff. You get governance controls, but you need to plan your licensing accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Groups
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fenvironment-groups-architecture.svg%3Fv%3D3a269b42" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fenvironment-groups-architecture.svg%3Fv%3D3a269b42" alt="Four environment groups showing Developer, Shared Dev, Test, and Production with governance rules per group" width="1200" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Environment groups let you organize environments and enforce rules at the group level. Instead of configuring sharing limits, solution checker, and other settings on each environment individually, you configure them once on the group and every environment in that group inherits the rules.&lt;/p&gt;

&lt;p&gt;This matters when you have 10, 20, or 50 environments. Configuring each one manually doesn't scale. Environment groups make it manageable.&lt;/p&gt;

&lt;p&gt;The recommended pattern:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment Group&lt;/th&gt;
&lt;th&gt;Contains&lt;/th&gt;
&lt;th&gt;Rules&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Developer environments&lt;/td&gt;
&lt;td&gt;All maker developer environments (auto-populated by routing)&lt;/td&gt;
&lt;td&gt;Sharing limited to 5 users, solution checker warns, usage insights on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared development&lt;/td&gt;
&lt;td&gt;Team dev environments for formal projects&lt;/td&gt;
&lt;td&gt;Sharing limited to security groups, solution checker warns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test / UAT&lt;/td&gt;
&lt;td&gt;Test environments for each project&lt;/td&gt;
&lt;td&gt;Sharing limited, solution checker blocks on errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production&lt;/td&gt;
&lt;td&gt;Live environments&lt;/td&gt;
&lt;td&gt;Strict sharing limits, solution checker blocks, full audit logging&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When environment routing creates a new developer environment, it can automatically place it in the Developer environments group. The maker gets a governed environment from day one without any admin intervention.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Building Power Platform governance?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Environment strategy is one layer of a complete governance framework. For more on naming conventions, solution awareness, and automated compliance, &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;follow Alex on LinkedIn&lt;/a&gt; for weekly Power Platform architecture posts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Connection References and Environment Variables
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fconnection-references-env-vars.svg%3Fv%3D3280518c" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fconnection-references-env-vars.svg%3Fv%3D3280518c" alt="Same flow across Dev Test and Prod environments with different connection references and environment variable values" width="1200" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are the bridge between environments. Without them, you can't move flows from dev to test to prod.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connection references&lt;/strong&gt; abstract the authentication. In dev, the connection reference points to your dev SharePoint site. In test, it points to the test site. In prod, the production site. The flow itself is identical across all three environments. Only the connection reference value changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment variables&lt;/strong&gt; store configuration that differs per environment. Email addresses, URLs, thresholds, feature flags. The flow references the variable, not the value. When you import the solution into a new environment, you set the variable values for that environment.&lt;/p&gt;

&lt;p&gt;Example of the same flow across three environments:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Dev&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Prod&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Flow name&lt;/td&gt;
&lt;td&gt;HR-Evaluation-Notify-OnStatusChange&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connection ref: contoso_outlook_hr&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:dev.maker@contoso.com"&gt;dev.maker@contoso.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:test.serviceaccount@contoso.com"&gt;test.serviceaccount@contoso.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:prod.serviceaccount@contoso.com"&gt;prod.serviceaccount@contoso.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Env var: contoso_HR_NotificationMailbox&lt;/td&gt;
&lt;td&gt;
&lt;a href="mailto:alex@contoso.com"&gt;alex@contoso.com&lt;/a&gt; (dev testing)&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:hr-test@contoso.com"&gt;hr-test@contoso.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:hr-notifications@contoso.com"&gt;hr-notifications@contoso.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Env var: contoso_HR_ApprovalThreshold&lt;/td&gt;
&lt;td&gt;0 (approve everything for testing)&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;5000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The flow logic never changes between environments. Only the configuration changes. This is what makes ALM possible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Name them consistently&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use the naming conventions from the first article in this series. When your flow is &lt;code&gt;HR-Evaluation-Notify-OnStatusChange&lt;/code&gt;, your connection reference is &lt;code&gt;contoso_outlook_hrnotifications&lt;/code&gt;, and your environment variable is &lt;code&gt;contoso_HR_NotificationMailbox&lt;/code&gt;, the entire chain is traceable by name alone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Full Picture
&lt;/h2&gt;

&lt;p&gt;Putting it all together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Makers&lt;/strong&gt; start in their own developer environment (created by environment routing)&lt;/li&gt;
&lt;li&gt;They build flows inside &lt;strong&gt;solutions&lt;/strong&gt; using &lt;strong&gt;connection references&lt;/strong&gt; and &lt;strong&gt;environment variables&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;When ready, they export the solution and import it into a &lt;strong&gt;shared test environment&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Business stakeholders validate in test&lt;/li&gt;
&lt;li&gt;The solution is promoted to &lt;strong&gt;production&lt;/strong&gt; as a managed solution&lt;/li&gt;
&lt;li&gt;Each environment is in an &lt;strong&gt;environment group&lt;/strong&gt; with appropriate governance rules&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;default environment&lt;/strong&gt; is locked down. No new flows are built there.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This isn't aspirational. This is the environment strategy that Microsoft recommends and that the platform supports today. The tooling exists. The licensing model supports it. The only thing missing in most organizations is the decision to implement it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with What You Have
&lt;/h2&gt;

&lt;p&gt;If you're running everything in the default environment today, here's the pragmatic path forward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a production environment&lt;/strong&gt; Provision a new environment with Dataverse. This becomes your target for business-critical flows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a dev environment&lt;/strong&gt; Provision a development environment. This is where makers build new flows going forward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable environment routing&lt;/strong&gt; Route new makers to developer environments. This prevents new flows from landing in the default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migrate critical flows&lt;/strong&gt; Move your most important flows into solutions in the dev environment. Deploy to production through managed solutions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable Managed Environments on production&lt;/strong&gt; Turn on Managed Environments for your production environment. Configure sharing limits and solution checker enforcement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradually migrate the rest&lt;/strong&gt; Work through the remaining flows in the default environment over weeks or months. Not everything needs to move at once.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal isn't to migrate everything overnight. The goal is to stop making the problem worse (new flows in the default environment) while gradually fixing the existing state.&lt;/p&gt;




&lt;h2&gt;
  
  
  Power Automate Governance - The Enterprise Playbook
&lt;/h2&gt;

&lt;p&gt;This article is part of a 10-part series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale/" rel="noopener noreferrer"&gt;Naming Conventions That Scale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;Environment Strategy - Dev Test Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm/" rel="noopener noreferrer"&gt;Solution-Aware Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see/" rel="noopener noreferrer"&gt;Flow Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-pipelines-moving-flows-from-dev-to-prod/" rel="noopener noreferrer"&gt;Pipelines - Dev to Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/coe-starter-kit-what-it-does-and-what-to-build-on-top/" rel="noopener noreferrer"&gt;CoE Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production/" rel="noopener noreferrer"&gt;AI-Powered Flow Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track/" rel="noopener noreferrer"&gt;Versioning and Source Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory/" rel="noopener noreferrer"&gt;The Governance Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-weekly-governance-digest-automated-health-report/" rel="noopener noreferrer"&gt;Weekly Governance Digest&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>devops</category>
      <category>powerautomate</category>
    </item>
    <item>
      <title>Power Automate Flow Inventory - You Can't Govern What You Can't See</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Sat, 19 Sep 2026 16:57:43 +0000</pubDate>
      <link>https://dev.to/az365ai/power-automate-flow-inventory-you-cant-govern-what-you-cant-see-1h8c</link>
      <guid>https://dev.to/az365ai/power-automate-flow-inventory-you-cant-govern-what-you-cant-see-1h8c</guid>
      <description>&lt;p&gt;Ask any IT leader how many Power Automate flows run in their tenant. The answer is almost always a guess. "Maybe 20 or 30." "A handful." "Not many."&lt;/p&gt;

&lt;p&gt;Then you run an actual Power Automate flow inventory. The real number is often 300, 800, or 2,000. A meaningful fraction are typically owned by people who no longer work at the company. Some haven't run successfully in months. Others connect to external services that IT never approved. Several may be sending data to personal OneDrive accounts. The CoE Starter Kit's &lt;a href="https://learn.microsoft.com/power-platform/guidance/coe/core-components" rel="noopener noreferrer"&gt;Maker dashboard documentation&lt;/a&gt; describes exactly this orphan-and-unsanctioned-flow pattern as the typical reason organizations install it in the first place.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most organizations drastically underestimate how many Power Automate flows exist in their tenant. Use PowerShell, admin connectors, or the CoE Starter Kit to build a complete flow inventory. Classify every flow by criticality, fix orphans, and set up continuous sync so the inventory stays current.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fflow-inventory-hero.svg%3Fv%3D01da5e60" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fflow-inventory-hero.svg%3Fv%3D01da5e60" alt="Iceberg diagram showing 10 visible flows above the line and 290 hidden flows below" width="612" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This isn't hypothetical. This is what happens in every organization where Power Platform adoption grew organically without governance. Users discover Power Automate, solve their own problems, and move on. Nobody tracks what was built. Nobody reviews what's running. Nobody knows what happens when those flows break.&lt;/p&gt;

&lt;p&gt;You can't govern what you can't see. The inventory is step one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do You Need a Power Automate Flow Inventory?
&lt;/h2&gt;

&lt;p&gt;Without a flow inventory, you cannot identify orphaned flows, enforce naming conventions, audit connector usage, or verify license compliance. A flow inventory gives administrators a single source of truth for every automation in the tenant, enabling informed governance decisions instead of guesswork.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovery Methods
&lt;/h2&gt;

&lt;p&gt;There are four ways to discover flows in your tenant, from simplest to most comprehensive.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Effort&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Automation&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Power Platform Admin Center&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Per environment&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Quick spot checks, small tenants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PowerShell cmdlets&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Per environment or all environments&lt;/td&gt;
&lt;td&gt;Scriptable&lt;/td&gt;
&lt;td&gt;Bulk export, one-time audits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin connectors in Power Automate&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;All environments&lt;/td&gt;
&lt;td&gt;Fully automated&lt;/td&gt;
&lt;td&gt;Ongoing monitoring, custom reporting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CoE Starter Kit Core module&lt;/td&gt;
&lt;td&gt;High (initial setup)&lt;/td&gt;
&lt;td&gt;All environments&lt;/td&gt;
&lt;td&gt;Fully automated, continuous sync&lt;/td&gt;
&lt;td&gt;Enterprise-scale governance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  1. Power Platform Admin Center
&lt;/h3&gt;

&lt;p&gt;The simplest approach. Navigate to admin.powerplatform.microsoft.com, select an environment, go to Resources, and click Flows. You get a list of all cloud flows in that environment with owner, status, and creation date.&lt;/p&gt;

&lt;p&gt;Limitations: you can only view one environment at a time. Filtering is basic. There's no export button for custom analysis. For a tenant with 3 environments, this is manageable. For a tenant with 30 environments, it's not practical.&lt;/p&gt;

&lt;p&gt;Best for: quick spot checks and small organizations.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. PowerShell Cmdlets
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Get-AdminFlow&lt;/code&gt; cmdlet from the Microsoft.PowerApps.Administration.PowerShell module returns detailed information about flows. You can script it to loop through all environments and export the results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install the module&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Install-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Microsoft.PowerApps.Administration.PowerShell&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Get all flows across all environments&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$environments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Get-AdminPowerAppEnvironment&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$allFlows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kr"&gt;foreach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$env&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$environments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$flows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Get-AdminFlow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-EnvironmentName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnvironmentName&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;foreach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$flow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$flows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nv"&gt;$allFlows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PSCustomObject&lt;/span&gt;&lt;span class="p"&gt;]@{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;FlowName&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$flow&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DisplayName&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;FlowId&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$flow&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FlowName&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$env&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DisplayName&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;CreatedBy&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$flow&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CreatedBy&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;CreatedTime&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$flow&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CreatedTime&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;LastModified&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$flow&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LastModifiedTime&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$flow&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Enabled&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$allFlows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Export-Csv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FlowInventory.csv"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NoTypeInformation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PowerShell returns the most up-to-date data because it queries the platform APIs directly. &lt;code&gt;Get-AdminFlow&lt;/code&gt; returns all cloud flows in an environment. You get flow name, ID, creator, creation date, last modified date, and enabled/disabled state.&lt;/p&gt;

&lt;p&gt;Best for: one-time audits, scripted bulk operations, and organizations comfortable with PowerShell.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Admin Connectors
&lt;/h3&gt;

&lt;p&gt;Power Platform provides admin connectors that you can use inside Power Automate flows themselves. This means you can build a flow that inventories all other flows. Recursive? Yes. Useful? Extremely.&lt;/p&gt;

&lt;p&gt;The relevant connectors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Power Automate Management&lt;/strong&gt; - list flows, get flow details, list flow runs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Power Automate for Admins&lt;/strong&gt; (Microsoft Flow for Admins) - disable flows, delete flows, administrative actions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Power Platform for Admins&lt;/strong&gt; - environment operations, DLP policies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You build a scheduled flow that runs daily or weekly, calls the admin connector to list all flows across environments, and writes the results to a Dataverse table or SharePoint list. This gives you a continuously updated inventory without manual effort.&lt;/p&gt;

&lt;p&gt;Best for: ongoing monitoring with custom logic. You can add classification rules, anomaly detection, and alerting directly in the flow.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. CoE Starter Kit Core Module
&lt;/h3&gt;

&lt;p&gt;The Center of Excellence Starter Kit is Microsoft's reference implementation for Power Platform governance. The Core module includes inventory flows that automatically sync all apps, flows, connectors, and environments to Dataverse tables.&lt;/p&gt;

&lt;p&gt;The inventory flows run on a driver/sync pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Admin | Sync Template v4 (Driver)&lt;/strong&gt; - orchestrates the sync process&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin | Sync Template v3 (Flows)&lt;/strong&gt; - gets cloud flow information using the Power Automate Management connector&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin | Sync Template v3 (Flow Action Details)&lt;/strong&gt; - (optional) gets the actions and triggers for every flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CoE Starter Kit stores inventory in Dataverse and includes Power BI dashboards for visualization. It handles the heavy lifting of discovery, deduplication, and incremental sync. The inventory flows only update objects modified since the last sync, reducing API consumption.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CoE Starter Kit sizing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The CoE Starter Kit using cloud flows for inventory is suitable for small to medium tenants. For tenants where Power Platform inventory exceeds 10,000 objects (combined environments, apps, flows), Microsoft recommends the data export integration, which is currently in experimental preview.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Best for: enterprise-scale governance. If you're serious about Power Platform governance, the CoE Starter Kit is the starting point. You'll likely customize it, but it provides the foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Capture Per Flow
&lt;/h2&gt;

&lt;p&gt;Running a discovery query is step one. Making the data useful is step two. Here is what you should capture for every flow in your inventory:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data Point&lt;/th&gt;
&lt;th&gt;Where to Get It&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Flow display name&lt;/td&gt;
&lt;td&gt;Get-AdminFlow / Admin connector&lt;/td&gt;
&lt;td&gt;Naming convention compliance check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flow ID&lt;/td&gt;
&lt;td&gt;Get-AdminFlow&lt;/td&gt;
&lt;td&gt;Unique identifier for programmatic management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Owner (user or service principal)&lt;/td&gt;
&lt;td&gt;Get-AdminFlow / flow details&lt;/td&gt;
&lt;td&gt;Orphan detection, license compliance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Environment&lt;/td&gt;
&lt;td&gt;Environment enumeration&lt;/td&gt;
&lt;td&gt;Which environment the flow lives in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trigger type&lt;/td&gt;
&lt;td&gt;Flow definition / Flow Action Details&lt;/td&gt;
&lt;td&gt;Understanding what starts the flow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connectors used&lt;/td&gt;
&lt;td&gt;Flow Action Details (CoE)&lt;/td&gt;
&lt;td&gt;Connector audit, DLP compliance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Last successful run date&lt;/td&gt;
&lt;td&gt;Flow run history&lt;/td&gt;
&lt;td&gt;Detecting abandoned flows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flow status (enabled/disabled)&lt;/td&gt;
&lt;td&gt;Get-AdminFlow&lt;/td&gt;
&lt;td&gt;Finding flows that silently stopped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solution membership&lt;/td&gt;
&lt;td&gt;Solution component query&lt;/td&gt;
&lt;td&gt;Identifying loose flows vs solution-aware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Created date&lt;/td&gt;
&lt;td&gt;Get-AdminFlow&lt;/td&gt;
&lt;td&gt;Age analysis, finding legacy flows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Description&lt;/td&gt;
&lt;td&gt;Flow details&lt;/td&gt;
&lt;td&gt;Documentation compliance check&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Classification Framework
&lt;/h2&gt;

&lt;p&gt;Raw inventory data is overwhelming. A flat list of 500 flows isn't actionable. Classification turns data into decisions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Classification&lt;/th&gt;
&lt;th&gt;Criteria&lt;/th&gt;
&lt;th&gt;Governance Level&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Business-critical&lt;/td&gt;
&lt;td&gt;Supports a core business process. Failure impacts revenue, compliance, or operations.&lt;/td&gt;
&lt;td&gt;Highest. Service principal ownership, managed solution, monitored 24/7.&lt;/td&gt;
&lt;td&gt;Invoice approval, regulatory reporting, customer onboarding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team productivity&lt;/td&gt;
&lt;td&gt;Department-level workflow. Failure impacts a team's efficiency but not the whole organization.&lt;/td&gt;
&lt;td&gt;Medium. Solution-aware, named correctly, owner tracked.&lt;/td&gt;
&lt;td&gt;Leave request approvals, team status reports, document routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Personal&lt;/td&gt;
&lt;td&gt;Individual automation. One person uses it for their own work.&lt;/td&gt;
&lt;td&gt;Low. Track in inventory, ensure no PII exposure.&lt;/td&gt;
&lt;td&gt;Email sorting rules, personal task reminders, calendar sync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Experimental&lt;/td&gt;
&lt;td&gt;Testing, learning, proof of concept. Not intended for ongoing use.&lt;/td&gt;
&lt;td&gt;Minimal. Track, auto-disable if inactive for 60 days.&lt;/td&gt;
&lt;td&gt;Hackathon projects, training exercises, connector testing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Classification should be a field in your inventory, not a separate spreadsheet. If you use the CoE Starter Kit, add a custom column to the flow inventory table. If you use a SharePoint list, add a choice column. The classification drives the governance response.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Orphan Problem
&lt;/h2&gt;

&lt;p&gt;An orphaned flow is a flow whose owner no longer has a valid account. The owner left the organization, their account was disabled, and the flow keeps running. Or tries to. Usually it starts failing because the connections tied to the owner's account no longer authenticate.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Detect Orphans
&lt;/h3&gt;

&lt;p&gt;In the Power Platform Admin Center, orphaned flows show no owner in the Owners column on the environment's flow resource page. In PowerShell, you can cross-reference the flow creator's user ID against Microsoft Entra to check if the account is still active.&lt;/p&gt;

&lt;p&gt;The CoE Starter Kit does this automatically. Its inventory flows track the maker's status and flag flows owned by disabled or deleted users.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Fix Orphans
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identify the orphan&lt;/strong&gt; Use admin center, PowerShell, or CoE inventory to find flows with invalid owners.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assess business impact&lt;/strong&gt; Is the flow still needed? Check the last run date and whether the business process it supports is still active.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assign a co-owner&lt;/strong&gt; In the admin center or via PowerShell (Set-AdminFlowOwnerRole), add a new co-owner to the flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix the connections&lt;/strong&gt; The new owner needs to re-authenticate any connections that were tied to the previous owner's account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider service principal ownership&lt;/strong&gt; For business-critical flows, change ownership to a service principal to prevent future orphaning.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Prevent Orphans by Design
&lt;/h3&gt;

&lt;p&gt;The best way to handle orphans is to prevent them. Service principal ownership is the answer for any flow that supports an organizational process.&lt;/p&gt;

&lt;p&gt;A service principal is a non-human identity in Microsoft Entra. It doesn't have a user account that can be disabled when someone leaves. It doesn't take vacation. It doesn't change roles. When a flow is owned by a service principal, the ownership is stable regardless of personnel changes.&lt;/p&gt;

&lt;p&gt;Key facts about service principal flow ownership:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service principals can own and run flows&lt;/li&gt;
&lt;li&gt;For solution-aware flows, connections don't need to be shared separately with the service principal&lt;/li&gt;
&lt;li&gt;Premium service principal flows need a Power Automate Process or per-flow license&lt;/li&gt;
&lt;li&gt;Standard (non-premium) service principal flows get 25,000 base requests per tenant per 24 hours&lt;/li&gt;
&lt;li&gt;Service principal flows in context of Dynamics 365 applications get higher limits from a tenant-level pool&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Don't put service principals on everything&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Service principal ownership is for mission-critical and team-level flows. Personal productivity flows should stay with the user. Over-engineering governance for low-risk flows wastes time and licenses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want more governance playbooks?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I write about Power Platform governance, ALM pipelines, and enterprise automation strategy. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow me on LinkedIn&lt;/a&gt; for weekly deep dives.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Connector Audit
&lt;/h2&gt;

&lt;p&gt;Your inventory should tell you which connectors each flow uses. This matters for three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DLP compliance.&lt;/strong&gt; Data Loss Prevention policies restrict which connectors can be used together. A flow that combines a SharePoint connector (business data) with a personal Dropbox connector (personal storage) might violate your DLP policy. Your inventory should flag these combinations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;External service exposure.&lt;/strong&gt; Which flows connect to services outside your organization? HTTP connectors, custom connectors, and third-party connectors can send data anywhere. You need to know which flows use them and what data they transmit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Premium connector licensing.&lt;/strong&gt; Flows that use premium connectors require premium licenses. Your inventory should identify which flows use premium connectors so you can ensure license compliance.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The CoE Starter Kit's optional Flow Action Details flow captures connector and action details for every flow. This is resource-intensive to run but provides the deepest visibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Output Format
&lt;/h2&gt;

&lt;p&gt;Where do you store the inventory?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Storage&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dataverse (via CoE Starter Kit)&lt;/td&gt;
&lt;td&gt;Enterprise tenants, ongoing governance&lt;/td&gt;
&lt;td&gt;Rich querying, Power BI integration, automated sync&lt;/td&gt;
&lt;td&gt;Requires Dataverse capacity, CoE setup effort&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SharePoint list&lt;/td&gt;
&lt;td&gt;Small to medium tenants, simpler governance&lt;/td&gt;
&lt;td&gt;Easy to set up, familiar interface, Power Automate integration&lt;/td&gt;
&lt;td&gt;Limited to 5,000 item threshold for views, no complex queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Excel / CSV&lt;/td&gt;
&lt;td&gt;One-time audits, snapshots&lt;/td&gt;
&lt;td&gt;Simple, exportable, shareable&lt;/td&gt;
&lt;td&gt;No automation, stale immediately after creation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For ongoing governance, Dataverse via the CoE Starter Kit is the right answer. It gives you a continuously updated, queryable inventory with Power BI dashboards out of the box. For smaller organizations or initial assessments, a SharePoint list with a weekly sync flow is a pragmatic starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping It Current
&lt;/h2&gt;

&lt;p&gt;An inventory that's accurate on the day you create it and wrong the next week isn't governance. It's a report.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Frequency&lt;/th&gt;
&lt;th&gt;Effort&lt;/th&gt;
&lt;th&gt;Accuracy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CoE Starter Kit automated sync&lt;/td&gt;
&lt;td&gt;Daily&lt;/td&gt;
&lt;td&gt;Zero (after initial setup)&lt;/td&gt;
&lt;td&gt;High. Only misses items created since last sync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduled PowerShell script&lt;/td&gt;
&lt;td&gt;Weekly or monthly&lt;/td&gt;
&lt;td&gt;Low (scheduled task)&lt;/td&gt;
&lt;td&gt;Good. Depends on run frequency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin connector flow&lt;/td&gt;
&lt;td&gt;Daily to weekly&lt;/td&gt;
&lt;td&gt;Low (after flow is built)&lt;/td&gt;
&lt;td&gt;Good. Customizable to your needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual audit&lt;/td&gt;
&lt;td&gt;Quarterly&lt;/td&gt;
&lt;td&gt;High. Someone has to do it&lt;/td&gt;
&lt;td&gt;Low. Outdated within days of completion&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The CoE Starter Kit's incremental sync is designed for this. By default, it only updates objects modified since the last inventory run (configurable via the &lt;code&gt;InventoryFilter_DaysToLookBack&lt;/code&gt; environment variable, default 7 days). If you need a full re-sync, set the &lt;code&gt;Full inventory&lt;/code&gt; environment variable to &lt;code&gt;Yes&lt;/code&gt;, run the driver flow, then set it back to &lt;code&gt;No&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Quarterly manual audits are the baseline. If you do nothing else, run a PowerShell export once per quarter, compare it to the previous quarter, and flag new flows, orphaned flows, and flows that stopped running. It's not ideal, but it's infinitely better than not knowing what exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Inventory to Action
&lt;/h2&gt;

&lt;p&gt;An inventory isn't the end goal. It's the foundation for governance decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flows without naming convention compliance?&lt;/strong&gt; Reach out to the makers, help them rename.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loose flows that should be in solutions?&lt;/strong&gt; Prioritize migration based on classification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orphaned flows?&lt;/strong&gt; Fix or decommission based on business need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flows using unapproved connectors?&lt;/strong&gt; Review, approve, or disable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flows that haven't run in 90 days?&lt;/strong&gt; Candidate for decommission.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flows owned by users without proper licenses?&lt;/strong&gt; Fix licensing or reassign ownership.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The inventory gives you the data. Your governance process gives you the actions. Without the inventory, you are governing blind. With it, you are making informed decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Here
&lt;/h2&gt;

&lt;p&gt;If you're starting from zero, here's the pragmatic path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run a PowerShell export&lt;/strong&gt; Use Get-AdminFlow across all environments. Export to CSV. This takes 30 minutes and gives you a baseline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Count and categorize&lt;/strong&gt; How many flows? How many environments? How many unique owners? How many are enabled vs disabled? Get the high-level numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identify orphans&lt;/strong&gt; Cross-reference flow owners with your user directory. Flag flows owned by departed employees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classify the top 20&lt;/strong&gt; Take the 20 most-used flows (by run count or business impact). Classify them as business-critical, team, personal, or experimental.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make the case for CoE Starter Kit&lt;/strong&gt; Use the numbers from your audit to justify the investment in the CoE Starter Kit. 'We have 400 flows, 60 are orphaned, and we had no idea' is a compelling governance story.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement continuous sync&lt;/strong&gt; Deploy the CoE Starter Kit or build your own admin connector flow. Move from point-in-time snapshots to continuous inventory.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The inventory is the foundation. Naming conventions tell you what a flow is. Environment strategy tells you where it lives. Solution awareness tells you how it deploys. But the inventory tells you what exists in the first place. Start there.&lt;/p&gt;




&lt;h2&gt;
  
  
  Power Automate Governance - The Enterprise Playbook
&lt;/h2&gt;

&lt;p&gt;This article is part of a 10-part series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale/" rel="noopener noreferrer"&gt;Naming Conventions That Scale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;Environment Strategy - Dev Test Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm/" rel="noopener noreferrer"&gt;Solution-Aware Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see/" rel="noopener noreferrer"&gt;Flow Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-pipelines-moving-flows-from-dev-to-prod/" rel="noopener noreferrer"&gt;Pipelines - Dev to Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/coe-starter-kit-what-it-does-and-what-to-build-on-top/" rel="noopener noreferrer"&gt;CoE Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production/" rel="noopener noreferrer"&gt;AI-Powered Flow Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track/" rel="noopener noreferrer"&gt;Versioning and Source Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory/" rel="noopener noreferrer"&gt;The Governance Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-weekly-governance-digest-automated-health-report/" rel="noopener noreferrer"&gt;Weekly Governance Digest&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>governance</category>
    </item>
    <item>
      <title>Living Documentation in Git - Why Your SharePoint Word Docs Are Dead</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Fri, 18 Sep 2026 17:23:58 +0000</pubDate>
      <link>https://dev.to/az365ai/living-documentation-in-git-why-your-sharepoint-word-docs-are-dead-4dmd</link>
      <guid>https://dev.to/az365ai/living-documentation-in-git-why-your-sharepoint-word-docs-are-dead-4dmd</guid>
      <description>&lt;p&gt;You open SharePoint. Navigate to the project folder. Find "Solution Design v3 FINAL (2).docx" from 8 months ago. Half the integrations described don't exist anymore. Three new ones aren't documented. The ERD shows tables that were renamed in sprint 4.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Put your living documentation in git next to your code. Markdown for text, Draw.io for diagrams. Docs update in the same commit as code changes, get reviewed in PRs, and never go stale in a forgotten SharePoint folder.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fliving-docs-hero.svg%3Fv%3Dd26f4059" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fliving-docs-hero.svg%3Fv%3Dd26f4059" alt="SharePoint Word docs with red X versus Git documentation with green checkmark" width="613" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nobody updated it because nobody opens SharePoint to update a Word doc after a deployment. The doc was accurate the day it was written. It started dying the day after.&lt;/p&gt;

&lt;p&gt;This is how most Dynamics 365 and Power Platform projects handle documentation. And it's why most projects have no useful documentation at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Living Documentation in Git Beat SharePoint Word Docs?
&lt;/h2&gt;

&lt;p&gt;Living documentation in git stays accurate because it versions alongside your code. SharePoint Word docs decay the moment they are saved, because they sit in a separate system that developers never touch during their normal workflow. Git-based docs get updated in the same pull request as the code change, reviewed by the same team, and tracked with the same history.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Is the Medium, Not the People
&lt;/h2&gt;

&lt;p&gt;Your team isn't lazy. The documentation process is broken.&lt;/p&gt;

&lt;p&gt;Word docs in SharePoint have three fatal flaws:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;They're disconnected from the code.&lt;/strong&gt; The solution ships from a git repo. The docs live in SharePoint. Nobody remembers to update both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They don't diff.&lt;/strong&gt; When someone edits a Word doc, you can't see what changed. Git shows you every line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They're invisible.&lt;/strong&gt; Developers live in VS Code and git. They never open SharePoint unless someone sends them a link.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Fix: Docs Live Next to Code
&lt;/h2&gt;

&lt;p&gt;Put your documentation in the same git repo as your solution. Markdown files. &lt;a href="https://az365.ai/blog/architecture-diagrams-with-draw-io-mcp-and-claude" rel="noopener noreferrer"&gt;Draw.io diagrams generated with Claude&lt;/a&gt;. Committed alongside the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-project/
  /docs
    architecture.md
    erd.drawio
    integration-map.drawio
    data-migration.md
  /pcf
    ... your PCF source
  /solution
    ... your Dataverse solution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a developer changes the schema, the ERD is right there in &lt;code&gt;/docs&lt;/code&gt;. When someone adds an integration, the architecture diagram is in the same pull request. When a new team member joins, they clone the repo and have everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Goes in /docs
&lt;/h2&gt;

&lt;p&gt;Not everything. Just the stuff that matters and changes with the code:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Document&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Why It Belongs in Git&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Architecture overview&lt;/td&gt;
&lt;td&gt;Markdown&lt;/td&gt;
&lt;td&gt;Changes when integrations change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entity Relationship Diagram&lt;/td&gt;
&lt;td&gt;Draw.io XML&lt;/td&gt;
&lt;td&gt;Changes when schema changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integration map&lt;/td&gt;
&lt;td&gt;Draw.io XML&lt;/td&gt;
&lt;td&gt;Changes when APIs change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data flow diagrams&lt;/td&gt;
&lt;td&gt;Draw.io XML&lt;/td&gt;
&lt;td&gt;Changes when migration logic changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration reference&lt;/td&gt;
&lt;td&gt;Markdown&lt;/td&gt;
&lt;td&gt;Changes when config options change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment runbook&lt;/td&gt;
&lt;td&gt;Markdown&lt;/td&gt;
&lt;td&gt;Changes when environments change&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What does NOT belong in git: meeting notes, project plans, status reports, contracts. Those belong in SharePoint or your PM tool. Git is for technical documentation that describes the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a /docs Folder Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;A typical Power Platform / D365 project repo following this pattern has a &lt;code&gt;/docs&lt;/code&gt; folder with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;architecture.md&lt;/code&gt; - ADRs (Architecture Decision Records) for every non-trivial choice&lt;/li&gt;
&lt;li&gt;ERD diagrams &lt;a href="https://az365.ai/blog/xrmtoolbox-schema-export-to-erd-with-claude" rel="noopener noreferrer"&gt;generated from Dataverse schema exports&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Integration maps showing system boundaries and data flows&lt;/li&gt;
&lt;li&gt;Configuration reference for JSON web resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The discipline is straightforward: when an entity is added, the ERD gets updated in the same commit. When an integration is added, the architecture doc gets a new ADR. The docs are never more than one commit behind the code.&lt;/p&gt;

&lt;p&gt;The figures below are illustrative diagrams generated from the Draw.io + Claude pipeline. They show the kinds of artifacts that belong in &lt;code&gt;/docs&lt;/code&gt; for a typical Power Platform engagement, not measurements from a specific client engagement. Names, role labels, and counts are illustrative.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fflow-inventory-map.svg%3Fv%3D144eb80e" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fflow-inventory-map.svg%3Fv%3D144eb80e" alt="Illustrative Power Automate flow inventory showing flows across categories with deployment status" width="960" height="520"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Illustrative flow inventory. Green = deployed, yellow = in development, gray = planned. The pattern: one diagram, kept current with every sprint, lives in git.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An end-to-end process diagram in the same &lt;code&gt;/docs&lt;/code&gt; folder might capture all roles, flows, and components in one visual:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fperformance-review-full-system.svg%3Fv%3Dedc7f2fe" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fperformance-review-full-system.svg%3Fv%3Dedc7f2fe" alt="Illustrative performance review process showing HR Admin, Evaluator, Approver, and System lanes with signing workflow and technology stack" width="1100" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Illustrative end-to-end process diagram. Roles and stack are example labels, not a specific engagement. The point: from setup through evaluation to archival, one diagram covers it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And the integration architecture showing how systems connect:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fintegration-architecture-d365.svg%3Fv%3Dac79e8e3" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fintegration-architecture-d365.svg%3Fv%3Dac79e8e3" alt="Illustrative D365 integration architecture with Azure Service Bus, AI Search, Power BI, and external ERP" width="900" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Illustrative architecture diagram generated with Claude and Draw.io. Lives in /docs, versioned with the code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This approach pairs naturally with a &lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory" rel="noopener noreferrer"&gt;governance repo&lt;/a&gt; where your standards, review checklists, and inventories also live as code.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Start
&lt;/h2&gt;

&lt;p&gt;You don't need to migrate everything at once. Pick one active project and do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a /docs folder in your repo&lt;/strong&gt; If you don't have one, add it. One folder, committed to git.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Move your ERD there&lt;/strong&gt; Export your current ERD (even if it's a screenshot) as a .drawio file or .md with a Mermaid diagram. Commit it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add architecture.md&lt;/strong&gt; Write three sentences: what the system does, what it integrates with, and what the deployment looks like. That's your starting point.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make it a habit&lt;/strong&gt; Every PR that changes schema or integrations includes a docs update. Review it like you review code.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You don't need to write it all yourself&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Claude can generate ERDs from schema exports, architecture docs from code structure, and integration maps from API specs. The AI generates the skeleton. You verify the specifics. More on this in the next articles in this series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Want more architecture and documentation patterns for Power Platform?&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for weekly deep dives on building systems that document themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;SharePoint Word Docs&lt;/th&gt;
&lt;th&gt;Docs in Git&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Updated when code changes&lt;/td&gt;
&lt;td&gt;Almost never&lt;/td&gt;
&lt;td&gt;Same commit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version history&lt;/td&gt;
&lt;td&gt;SharePoint versions (hard to compare)&lt;/td&gt;
&lt;td&gt;Git diff (line by line)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discoverable by developers&lt;/td&gt;
&lt;td&gt;Requires a link from someone&lt;/td&gt;
&lt;td&gt;Right there when you clone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reviewed in PRs&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works offline&lt;/td&gt;
&lt;td&gt;SharePoint needs internet&lt;/td&gt;
&lt;td&gt;Local clone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Searchable in IDE&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;grep / Ctrl+Shift+F&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;This is the first post in a series on modern technical documentation for Power Platform and D365 projects. Next up: generating architecture diagrams with Draw.io and Claude - no Visio license required.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/living-documentation-in-git-why-sharepoint-word-docs-are-dead/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>dynamics365</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Solution-Aware Power Automate Flows - Why Loose Flows Kill Your ALM</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Thu, 17 Sep 2026 17:52:41 +0000</pubDate>
      <link>https://dev.to/az365ai/solution-aware-power-automate-flows-why-loose-flows-kill-your-alm-4ll1</link>
      <guid>https://dev.to/az365ai/solution-aware-power-automate-flows-why-loose-flows-kill-your-alm-4ll1</guid>
      <description>&lt;p&gt;There are two kinds of Power Automate cloud flows. Solution-aware flows live inside a Dataverse solution. Non-solution flows - loose flows - live outside of solutions entirely. The difference determines whether you can govern, deploy, and manage the flow, or whether it's a one-off artifact tied to a single person in a single environment.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Solution-aware Power Automate flows can be exported, version-tracked, and deployed across environments. Loose flows cannot. Enable the "Create in Dataverse solutions" tenant setting and migrate existing loose flows using PowerShell or the manual add-to-solution method. Loose flows are technical debt waiting to break.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fsolution-aware-flows-hero.svg%3Fv%3Ddbd183cd" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fsolution-aware-flows-hero.svg%3Fv%3Ddbd183cd" alt="Loose scattered flows versus flows organized inside a Dataverse solution container" width="583" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most citizen-developer flows are loose. The maker clicked "Create" from the Power Automate home page, built the flow, saved it, and moved on. It works. It runs. It does what they need. But it exists outside of any solution, which means it exists outside of your ALM pipeline, outside of your governance model, and outside of your ability to manage it at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes a Flow Solution-Aware in Power Automate?
&lt;/h2&gt;

&lt;p&gt;A solution-aware flow is a cloud flow that exists inside a Dataverse solution. This means it participates in the standard Power Platform ALM lifecycle: export, import, version tracking, connection references, and environment variables. Any flow created outside a solution is considered "loose" and lacks these capabilities entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution-Aware vs Non-Solution Flows
&lt;/h2&gt;

&lt;p&gt;Here's what you gain when a flow is solution-aware, and what you lose when it's not:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Solution-Aware Flow&lt;/th&gt;
&lt;th&gt;Non-Solution (Loose) Flow&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Export/import between environments&lt;/td&gt;
&lt;td&gt;Yes, through solution transport&lt;/td&gt;
&lt;td&gt;No. Must be manually recreated or use legacy zip export&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connection references&lt;/td&gt;
&lt;td&gt;Yes. Connections abstracted for multi-environment deployment&lt;/td&gt;
&lt;td&gt;No. Connections hardcoded to the maker's account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Environment variables&lt;/td&gt;
&lt;td&gt;Yes. Config values change per environment&lt;/td&gt;
&lt;td&gt;No. Values hardcoded in the flow definition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Managed solution deployment&lt;/td&gt;
&lt;td&gt;Yes. Lock down the flow in production&lt;/td&gt;
&lt;td&gt;Not available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version history&lt;/td&gt;
&lt;td&gt;Yes. Drafts and versioning GA since February 2025&lt;/td&gt;
&lt;td&gt;No version history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Save as draft&lt;/td&gt;
&lt;td&gt;Yes. Save incomplete work without publishing&lt;/td&gt;
&lt;td&gt;No. Every save is live&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source control via solutions&lt;/td&gt;
&lt;td&gt;Yes. Export solution, commit to git or Azure DevOps&lt;/td&gt;
&lt;td&gt;Not possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dataverse-backed run history&lt;/td&gt;
&lt;td&gt;Yes. Run history stored in Dataverse for richer reporting&lt;/td&gt;
&lt;td&gt;Run history in legacy storage only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin visibility&lt;/td&gt;
&lt;td&gt;Visible in solution explorer, easier to inventory&lt;/td&gt;
&lt;td&gt;Harder to track, must use admin APIs or PowerShell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Owner leaves the organization&lt;/td&gt;
&lt;td&gt;Can be managed through solution ownership and sharing&lt;/td&gt;
&lt;td&gt;Flow becomes orphaned. May stop running.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The gap isn't subtle. A loose flow is a dead end for governance. You can't move it between environments through the standard ALM pipeline. You can't deploy it as part of a managed solution. You can't use connection references or environment variables. When the maker who built it leaves the organization, the flow becomes an orphan - still running (maybe), but nobody knows how to edit it because the connections are tied to a user account that no longer exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Loose Flows Are Dangerous
&lt;/h2&gt;

&lt;p&gt;The orphan problem deserves its own section because it's the most common way loose flows cause real damage.&lt;/p&gt;

&lt;p&gt;Here's the scenario. A maker builds a flow that sends daily sales reports to the VP. It uses the maker's Outlook connection to send the email and the maker's SharePoint connection to read the report data. The flow runs every morning at 7 AM. It works perfectly for 18 months.&lt;/p&gt;

&lt;p&gt;Then the maker leaves the company. Their account is disabled. The Outlook connection fails because the user no longer exists. The SharePoint connection fails for the same reason. The flow starts failing silently. Nobody notices for two weeks until the VP asks why they stopped getting reports.&lt;/p&gt;

&lt;p&gt;Now what? The flow isn't in a solution. You can't export it. You can't import it into another environment. The connections are dead. An admin can add a co-owner to the flow, but the new owner still needs to recreate every connection. If the flow is complex - branching logic, error handling, parallel branches - reconstructing it takes hours.&lt;/p&gt;

&lt;p&gt;If the flow had been in a solution with connection references, the fix would have been: update the connection reference to point to a service account or another user's connection. Five minutes, no flow editing required.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Loose flows are technical debt&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every loose flow in your tenant is a future problem. It might work today. It will break when the owner leaves, when you need to move it to a new environment, or when you need to audit what it does. The only question is when, not if.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to Make Existing Flows Solution-Aware
&lt;/h2&gt;

&lt;p&gt;You have two options for migrating existing loose flows into solutions: manual (one at a time) or bulk (PowerShell).&lt;/p&gt;

&lt;h3&gt;
  
  
  Manual: Add to a Solution
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open Power Automate and navigate to Solutions&lt;/strong&gt; Sign in to make.powerautomate.com. Select Solutions from the left navigation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open your target solution&lt;/strong&gt; Select the solution where you want to add the flow. If you don't have one, create a new solution with your publisher prefix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add existing &amp;gt; Automation &amp;gt; Cloud flow&lt;/strong&gt; Click Add existing, then Automation, then Cloud flow. You'll see two tabs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the Outside Dataverse tab&lt;/strong&gt; Non-solution flows appear on the Outside Dataverse tab. Solution-aware flows appear on the From Dataverse tab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select the flow and add it&lt;/strong&gt; Select the flow you want to migrate and click Add. The flow is now solution-aware.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Not all loose flows can be added&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some non-solution cloud flows can't be added to a solution due to known limitations. Flows with certain connector types or configurations may not be compatible. Check Microsoft's current documentation on solution limitations if you encounter errors.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Bulk: PowerShell Add-AdminFlowsToSolution
&lt;/h3&gt;

&lt;p&gt;For tenants with hundreds of loose flows, the manual approach doesn't scale. Use the &lt;code&gt;Add-AdminFlowsToSolution&lt;/code&gt; PowerShell cmdlet to migrate many flows at once.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install the Power Apps admin module if not already installed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Install-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Microsoft.PowerApps.Administration.PowerShell&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Migrate flows to a solution&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Add-AdminFlowsToSolution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;-EnvironmentName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-environment-id"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;-SolutionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-solution-id"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cmdlet accepts parameters to target flows by name or ID, so you can migrate in batches rather than all at once. This is the recommended approach for large-scale migrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make All New Flows Solution-Aware by Default
&lt;/h2&gt;

&lt;p&gt;This is the single most impactful tenant setting for Power Automate governance. When enabled, every new cloud flow is automatically created inside a Dataverse solution. No manual step required. No reliance on maker discipline.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open Power Platform admin center&lt;/strong&gt; Navigate to admin.powerplatform.microsoft.com.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select the target environment&lt;/strong&gt; Go to Environments and select the environment you want to configure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigate to Settings &amp;gt; Product &amp;gt; Features&lt;/strong&gt; Open the environment settings and find the Features section under Product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable Cloud flows under 'Create new canvas apps and cloud flows in Dataverse solutions'&lt;/strong&gt; Toggle the Cloud flows option to On. This ensures all new flows are solution-aware by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeat for every environment&lt;/strong&gt; Apply this setting to all environments where makers create flows.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;New environments have this enabled by default&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As of the current Power Platform release, all new environments provisioned with a Dataverse database have the Cloud flows setting enabled by default. You only need to manually enable it on older environments that were created before this default changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get more Power Platform governance insights&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I share hands-on ALM patterns, solution architecture tips, and governance strategies for Power Platform teams. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow me on LinkedIn&lt;/a&gt; for weekly deep dives.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Connection References and Environment Variables in Solutions
&lt;/h2&gt;

&lt;p&gt;Solution-aware flows use connection references and environment variables to abstract authentication and configuration from the flow definition. The flow stays identical across dev, test, and prod -- only the connection mappings and variable values change per environment. See the &lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;environment strategy article&lt;/a&gt; for the full setup, naming conventions, and a worked example across three environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managed vs Unmanaged Solutions
&lt;/h2&gt;

&lt;p&gt;This is a common source of confusion. When should you use managed solutions, and when should you use unmanaged?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Unmanaged Solution&lt;/th&gt;
&lt;th&gt;Managed Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Editable in target&lt;/td&gt;
&lt;td&gt;Yes. Anyone with access can modify&lt;/td&gt;
&lt;td&gt;No. Components are locked down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use in dev&lt;/td&gt;
&lt;td&gt;Yes. This is your working copy&lt;/td&gt;
&lt;td&gt;No. You don't import managed into dev&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use in test&lt;/td&gt;
&lt;td&gt;Sometimes, for flexibility during UAT&lt;/td&gt;
&lt;td&gt;Yes, for production-like testing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use in prod&lt;/td&gt;
&lt;td&gt;No. Too risky. Anyone can break it&lt;/td&gt;
&lt;td&gt;Yes. This is the standard for production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can be uninstalled&lt;/td&gt;
&lt;td&gt;Components remain after removal&lt;/td&gt;
&lt;td&gt;Clean uninstall removes all components&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version tracking&lt;/td&gt;
&lt;td&gt;No formal versioning&lt;/td&gt;
&lt;td&gt;Version numbers tracked on import&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The standard pattern: develop in an unmanaged solution in your dev environment. Export as managed. Import managed into test and production. This ensures production flows can't be edited directly. Changes must go through the dev environment and the ALM pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flow Drafts and Versioning
&lt;/h2&gt;

&lt;p&gt;Since February 2025, solution-aware flows support drafts and versioning. This is a significant capability gap that loose flows don't have.&lt;/p&gt;

&lt;p&gt;With drafts, you can save an incomplete flow without it going live. Make changes, save as draft, come back later. The published version continues to run while you iterate on the draft. When you're ready, publish the new version.&lt;/p&gt;

&lt;p&gt;Version history shows every published version. You can review previous versions, see what changed, and understand the evolution of the flow over time. This is basic version control that every other software development discipline takes for granted. Power Automate now has it for solution-aware flows.&lt;/p&gt;

&lt;p&gt;Loose flows have neither drafts nor versioning. Every save is immediately live. There's no way to save work in progress. There's no history of previous versions. If you save a broken change, it's immediately live and running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and Known Issues
&lt;/h2&gt;

&lt;p&gt;Solution-aware flows are the right choice, but they're not without limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Some connectors have limited solution support.&lt;/strong&gt; Check the connector documentation for solution awareness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migrating existing loose flows may require rework.&lt;/strong&gt; Flows with certain trigger types or connector configurations may need adjustments after migration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection references require planning.&lt;/strong&gt; You need to set up connection references before deployment, not after.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not all flow features work identically in solutions.&lt;/strong&gt; Test thoroughly after migration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legacy zip export still works for loose flows&lt;/strong&gt; but isn't recommended for production ALM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite these limitations, the direction is clear. Microsoft is investing heavily in solution-aware flows. Drafts, versioning, Dataverse-backed run history, and the default creation setting all point toward solution-aware as the standard. Loose flows are the legacy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Migration Priority
&lt;/h2&gt;

&lt;p&gt;You don't need to migrate every loose flow today. Prioritize:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Business-critical flows&lt;/strong&gt; that support core processes. These need ALM and governance first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flows owned by people who might leave.&lt;/strong&gt; Reduce orphan risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flows that need multi-environment deployment.&lt;/strong&gt; Solution awareness is a prerequisite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Everything else.&lt;/strong&gt; Work through the backlog over time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For personal productivity flows that a single user runs for themselves, the risk of leaving them loose is low. Focus your effort on the flows that matter to the organization.&lt;/p&gt;




&lt;h2&gt;
  
  
  Power Automate Governance - The Enterprise Playbook
&lt;/h2&gt;

&lt;p&gt;This article is part of a 10-part series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale/" rel="noopener noreferrer"&gt;Naming Conventions That Scale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;Environment Strategy - Dev Test Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm/" rel="noopener noreferrer"&gt;Solution-Aware Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see/" rel="noopener noreferrer"&gt;Flow Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-pipelines-moving-flows-from-dev-to-prod/" rel="noopener noreferrer"&gt;Pipelines - Dev to Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/coe-starter-kit-what-it-does-and-what-to-build-on-top/" rel="noopener noreferrer"&gt;CoE Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production/" rel="noopener noreferrer"&gt;AI-Powered Flow Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track/" rel="noopener noreferrer"&gt;Versioning and Source Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory/" rel="noopener noreferrer"&gt;The Governance Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-weekly-governance-digest-automated-health-report/" rel="noopener noreferrer"&gt;Weekly Governance Digest&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>devops</category>
      <category>powerautomate</category>
    </item>
    <item>
      <title>Power Automate Versioning and Source Control - Export Tag Track</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Wed, 16 Sep 2026 17:53:26 +0000</pubDate>
      <link>https://dev.to/az365ai/power-automate-versioning-and-source-control-export-tag-track-2ed5</link>
      <guid>https://dev.to/az365ai/power-automate-versioning-and-source-control-export-tag-track-2ed5</guid>
      <description>&lt;p&gt;You changed a Power Automate flow last Tuesday. Something broke in production on Thursday. You want to compare what the flow looked like before and after your change. You open the flow designer and see... the current version. That's it.&lt;/p&gt;

&lt;p&gt;There is no "show me last Tuesday's version." There is no diff view. There is no blame history. Power Automate versioning and source control require you to get flow definitions out of the platform and into git. Solution versioning tracks the whole solution, not individual flows. If your solution has 30 flows and you changed one, the version history tells you the solution changed. Not which flow. Not what changed inside it.&lt;/p&gt;

&lt;p&gt;This is the gap that kills teams at scale. You can't govern what you can't track.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Power Automate has no built-in version control for individual flows. Export flow definitions to git using Dataverse Git integration (Azure DevOps) or pac CLI (any git host). Once in git, you get branching, diffing, tagging, and pull request reviews. Use AI to summarize JSON diffs and even rewrite flow definitions for targeted improvements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fversioning-source-control-hero.svg%3Fv%3Da913c020" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fversioning-source-control-hero.svg%3Fv%3Da913c020" alt="Git timeline with tagged flow versions and diff capabilities" width="841" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Version Control Power Automate Flows?
&lt;/h2&gt;

&lt;p&gt;You export flow definition JSON from Dataverse into a git repository, either through the native Dataverse Git integration or the pac CLI. From there, every change becomes a commit, every release gets a tag, and you can diff any two versions to see exactly what changed inside a flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The State of Flow Versioning in 2026
&lt;/h2&gt;

&lt;p&gt;Power Automate gives you a few things out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run history.&lt;/strong&gt; You can see past executions and their inputs/outputs. Useful for debugging, not for understanding what changed in the flow definition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution versioning.&lt;/strong&gt; Solutions have version numbers (1.0.0.0, 1.1.0.0). But the version applies to the entire solution, not individual components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;28-day auto-save.&lt;/strong&gt; Cloud flows keep versions for 28 days in the designer. You can restore a previous version. But you can't compare two versions side by side. And after 28 days, they're gone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is source control. Source control means: every change is recorded, every version is retrievable, and you can compare any two versions line by line.&lt;/p&gt;

&lt;p&gt;To get real source control for flows, you need to get the flow definitions out of Dataverse and into git.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Paths to Git
&lt;/h2&gt;

&lt;p&gt;There are two approaches. Microsoft's built-in Dataverse Git integration (GA since April 2025) and the manual pac CLI workflow that teams have been using for years.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Dataverse Git Integration&lt;/th&gt;
&lt;th&gt;Manual pac CLI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup effort&lt;/td&gt;
&lt;td&gt;Medium - requires Managed Environments, Azure DevOps&lt;/td&gt;
&lt;td&gt;Low - just install pac CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git provider&lt;/td&gt;
&lt;td&gt;Azure DevOps only (no GitHub)&lt;/td&gt;
&lt;td&gt;Any git host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sync mechanism&lt;/td&gt;
&lt;td&gt;Commit/push from maker portal or API&lt;/td&gt;
&lt;td&gt;Manual export and unpack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Granularity&lt;/td&gt;
&lt;td&gt;Individual component files&lt;/td&gt;
&lt;td&gt;Individual component files (after unpack)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automation&lt;/td&gt;
&lt;td&gt;Can be triggered via API&lt;/td&gt;
&lt;td&gt;Script it yourself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requires Managed Environments&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Orgs already on Azure DevOps with Managed Environments&lt;/td&gt;
&lt;td&gt;Everyone else, or teams wanting full control&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both approaches end up in the same place: flow definitions as JSON files in a git repo, one file per flow, diffable and taggable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Path 1: Dataverse Git Integration
&lt;/h2&gt;

&lt;p&gt;Microsoft shipped Dataverse Git integration as GA in April 2025. It syncs solution components from a development environment to an Azure DevOps Git repo.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enable Managed Environments&lt;/strong&gt; Dataverse Git integration requires Managed Environments. Go to the Power Platform Admin Center, select your dev environment, and enable managed mode. This is a prerequisite you cannot skip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create an Azure DevOps repo&lt;/strong&gt; Create a new repo in Azure DevOps (or use an existing one). This is where your solution components will land. GitHub is not supported natively as of March 2026.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connect the environment to the repo&lt;/strong&gt; In the Power Platform Admin Center, go to your environment settings and configure the Git integration. Choose the Azure DevOps org, project, repo, and branch. Pick a folder path for the solution files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose a binding strategy&lt;/strong&gt; You have two options. Environment binding ties the connection to the environment itself. Solution binding ties it to a specific solution. Environment binding is simpler for single-solution dev environments. Solution binding gives you more control when one environment has multiple solutions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commit from the environment&lt;/strong&gt; From the maker portal (or via API), commit changes to the connected git repo. Each component gets its own file. Flows land as individual JSON definitions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pull changes back&lt;/strong&gt; You can pull from git into the environment to sync changes made by other developers. This is how multi-developer scenarios work - each dev has their own environment, all syncing to the same repo.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Dev environments only&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dataverse Git integration is designed for development environments. You do not sync production or test environments to git. Those environments get updated through deployment pipelines. The flow is: dev environment syncs to git, pipelines deploy from git to test, then to production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The big advantage: makers can commit directly from the Power Platform maker portal. No CLI. No scripts. The big limitation: Azure DevOps only. If your team uses GitHub, you'll need the pac CLI approach or a mirror setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Path 2: Manual pac CLI Workflow
&lt;/h2&gt;

&lt;p&gt;The Power Platform CLI (pac) has been around longer and works with any git host. The workflow is more manual but gives you complete control.&lt;/p&gt;

&lt;p&gt;The key commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Export a solution as a ZIP file&lt;/span&gt;
pac solution &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; YourSolution &lt;span class="nt"&gt;--path&lt;/span&gt; ./exports/YourSolution.zip

&lt;span class="c"&gt;# Unpack the ZIP into individual component files&lt;/span&gt;
pac solution unpack &lt;span class="nt"&gt;--zipfile&lt;/span&gt; ./exports/YourSolution.zip &lt;span class="nt"&gt;--folder&lt;/span&gt; ./src/YourSolution

&lt;span class="c"&gt;# After making changes, re-pack for import&lt;/span&gt;
pac solution pack &lt;span class="nt"&gt;--folder&lt;/span&gt; ./src/YourSolution &lt;span class="nt"&gt;--zipfile&lt;/span&gt; ./exports/YourSolution.zip

&lt;span class="c"&gt;# Generate deployment settings (connection references, env variables)&lt;/span&gt;
pac solution create-settings &lt;span class="nt"&gt;--solution-zip&lt;/span&gt; ./exports/YourSolution.zip &lt;span class="nt"&gt;--settings-file&lt;/span&gt; ./settings/dev-settings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you unpack a solution, flows land in the &lt;code&gt;Workflows/&lt;/code&gt; folder as individual JSON files. Each flow has its own file named with its GUID and display name. The JSON contains the full flow definition - every action, every condition, every expression.&lt;/p&gt;

&lt;p&gt;Your repo structure ends up looking like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-solution-repo/
  src/
    YourSolution/
      Workflows/
        FlowA-{guid}.json
        FlowB-{guid}.json
        FlowC-{guid}.json
      Entities/
        ...
      PluginAssemblies/
        ...
      Other/
        Solution.xml
        Customizations.xml
  exports/
    YourSolution.zip
  settings/
    dev-settings.json
    test-settings.json
    prod-settings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Git Workflow
&lt;/h2&gt;

&lt;p&gt;Once your flow definitions are in git - whether through Dataverse Git integration or pac CLI - you treat them like any other code artifact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Branching.&lt;/strong&gt; One branch per feature or change. If you're modifying the approval flow and the notification flow, that's one branch with changes to two JSON files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commits.&lt;/strong&gt; Meaningful commit messages that describe what changed in business terms. Not "updated flow" but "Added retry logic to vendor approval flow - 3 attempts with exponential backoff."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tags.&lt;/strong&gt; Tag solution versions when you deploy. &lt;code&gt;v1.0.0.0&lt;/code&gt; matches solution version 1.0.0.0 in Dataverse. When something breaks in production, you can check out the exact version that's running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Tag a release&lt;/span&gt;
git tag &lt;span class="nt"&gt;-a&lt;/span&gt; v1.2.0.0 &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Release 1.2.0.0 - added vendor approval retry logic"&lt;/span&gt;

&lt;span class="c"&gt;# List tags&lt;/span&gt;
git tag &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"v1.*"&lt;/span&gt;

&lt;span class="c"&gt;# Check out a specific version&lt;/span&gt;
git checkout v1.1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pull requests.&lt;/strong&gt; Every flow change goes through a PR. The reviewer sees the JSON diff. They can see that you added a new action, changed a condition, or modified an expression. It's not as readable as code, but it's infinitely better than "trust me, I changed the flow."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Following along with the governance series?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I publish new Power Platform governance patterns every week. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow me on LinkedIn&lt;/a&gt; so you don't miss the next article in this 10-part series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Diffing Flow Versions
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. Flow definitions are JSON. JSON diffs in git.&lt;/p&gt;

&lt;p&gt;When you compare two commits, you see exactly what changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Before&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Send_approval"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OpenApiConnectionWebhook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"approvalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"First to respond"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;After&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Send_approval"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OpenApiConnectionWebhook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"approvalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Everyone must approve"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that someone changed the approval from "First to respond" to "Everyone must approve." In the designer, you'd have to open both versions (if you still have them) and click into each action to find the difference.&lt;/p&gt;

&lt;p&gt;But raw JSON diffs of complex flows are hard to read. A flow with 40 actions produces a JSON file that's thousands of lines long. Finding the meaningful change in a 200-line diff is tedious.&lt;/p&gt;

&lt;p&gt;This is where AI helps. Copy the diff output and ask an AI to summarize it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here is a git diff of a Power Automate flow definition (JSON).
Summarize the changes in plain English:
- What actions were added, removed, or modified?
- What conditions changed?
- What expressions were updated?
- Are there any potential issues with the changes?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI reads the JSON diff and gives you something like: "The approval action was changed from single-approver to all-must-approve. A new parallel branch was added for a notification to the requester. The error handling scope was extended to cover the new branch." That's a code review you can actually work with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rewriting Flows with AI
&lt;/h2&gt;

&lt;p&gt;This is experimental but powerful. Export a flow's JSON definition, give it to an AI, and ask for specific improvements.&lt;/p&gt;

&lt;p&gt;Things that work well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Add error handling.&lt;/strong&gt; "Wrap each HTTP action in a try-catch scope with retry policy and failure notification."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rename variables.&lt;/strong&gt; "Change all variables from Hungarian notation (strApproverEmail) to descriptive names (approver_email_address)."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add comments.&lt;/strong&gt; Flow JSON supports a &lt;code&gt;description&lt;/code&gt; field on actions and scopes. Ask the AI to add descriptions explaining the business logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimize expressions.&lt;/strong&gt; "Simplify this nested if/coalesce chain into a cleaner expression."&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Always test in dev first&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Importing modified flow JSON can break connection references. The flow JSON contains connection IDs that are environment-specific. If you modify the JSON and import it, connection references may not resolve correctly. Always import to a dev environment first. Reconnect any broken connections. Test the flow end to end before promoting to test or production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The workflow for AI-assisted flow rewriting:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Export and unpack the solution (pac CLI or git sync)&lt;/li&gt;
&lt;li&gt;Copy the specific flow's JSON file&lt;/li&gt;
&lt;li&gt;Give it to the AI with specific instructions for what to improve&lt;/li&gt;
&lt;li&gt;Review the output carefully. Check that connection references, trigger configuration, and environment-specific values weren't changed&lt;/li&gt;
&lt;li&gt;Replace the flow JSON in your unpacked solution&lt;/li&gt;
&lt;li&gt;Pack the solution and import to dev&lt;/li&gt;
&lt;li&gt;Test every path. Especially error paths.&lt;/li&gt;
&lt;li&gt;Once validated, commit to git and promote through your pipeline&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is not a "let AI rewrite everything" approach. It's targeted refactoring of specific flows where you know what you want to improve. The AI handles the tedious JSON manipulation. You handle the validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;A government services team I worked with had 45 flows across 3 solutions. No version control. Changes went directly into the production environment. When something broke, the fix was "let me try to remember what I changed."&lt;/p&gt;

&lt;p&gt;We set up pac CLI exports on a weekly schedule. Every Monday, an Azure DevOps pipeline ran &lt;code&gt;pac solution export&lt;/code&gt; and &lt;code&gt;pac solution unpack&lt;/code&gt; for each solution, committed the results to git, and tagged the version. Total automation effort: one afternoon.&lt;/p&gt;

&lt;p&gt;Within two weeks, the team caught a flow modification that removed an error handling scope. The weekly diff showed the scope was gone. Without git, nobody would have noticed until a failure hit production.&lt;/p&gt;

&lt;p&gt;Within a month, the team started doing manual exports before and after each change. Not because someone mandated it. Because they could see the value of tracking what changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Don't try to set up the full pipeline on day one. Start with this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install pac CLI: &lt;code&gt;dotnet tool install --global Microsoft.PowerApps.CLI.Tool&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Authenticate: &lt;code&gt;pac auth create --url https://your-org.crm.dynamics.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Export your most critical solution: &lt;code&gt;pac solution export --name YourSolution --path ./YourSolution.zip&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Unpack it: &lt;code&gt;pac solution unpack --zipfile ./YourSolution.zip --folder ./YourSolution&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Initialize a git repo: &lt;code&gt;git init &amp;amp;&amp;amp; git add . &amp;amp;&amp;amp; git commit -m "Initial export of YourSolution v1.0.0.0"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Push to Azure DevOps or GitHub&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You now have version control for your flows. Every export from this point forward is a new commit. Every commit is a diffable snapshot.&lt;/p&gt;

&lt;p&gt;From there, add branching, PRs, tags, and automation as the team matures. The important thing is to start capturing the history.&lt;/p&gt;




&lt;h2&gt;
  
  
  Power Automate Governance - The Enterprise Playbook
&lt;/h2&gt;

&lt;p&gt;This article is part of a 10-part series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale/" rel="noopener noreferrer"&gt;Naming Conventions That Scale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;Environment Strategy - Dev Test Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm/" rel="noopener noreferrer"&gt;Solution-Aware Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see/" rel="noopener noreferrer"&gt;Flow Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-pipelines-moving-flows-from-dev-to-prod/" rel="noopener noreferrer"&gt;Pipelines - Dev to Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/coe-starter-kit-what-it-does-and-what-to-build-on-top/" rel="noopener noreferrer"&gt;CoE Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production/" rel="noopener noreferrer"&gt;AI-Powered Flow Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track/" rel="noopener noreferrer"&gt;Versioning and Source Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory/" rel="noopener noreferrer"&gt;The Governance Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-weekly-governance-digest-automated-health-report/" rel="noopener noreferrer"&gt;Weekly Governance Digest&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>devops</category>
      <category>powerautomate</category>
    </item>
    <item>
      <title>Power Platform Pipelines - Moving Flows from Dev to Prod with Approvals</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Tue, 15 Sep 2026 17:51:25 +0000</pubDate>
      <link>https://dev.to/az365ai/power-platform-pipelines-moving-flows-from-dev-to-prod-with-approvals-33oj</link>
      <guid>https://dev.to/az365ai/power-platform-pipelines-moving-flows-from-dev-to-prod-with-approvals-33oj</guid>
      <description>&lt;p&gt;"How do you deploy flows to production?"&lt;/p&gt;

&lt;p&gt;I ask this question in every governance workshop. The most common answer is still "export as managed, import manually, cross fingers." Sometimes they use Azure DevOps pipelines. Sometimes it is a SharePoint list with "ready to deploy" statuses and a person who runs imports on Tuesday mornings.&lt;/p&gt;

&lt;p&gt;Microsoft shipped a first-party ALM tool called Power Platform Pipelines. It has been GA since mid-2025. It lives inside the platform itself. No Azure DevOps subscription needed. No YAML. No pipeline agents. And most organizations running Power Platform today do not know it exists.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Power Platform Pipelines give you built-in CI/CD for Dataverse solutions with approval gates, connection mapping, and solution validation. Configure once, then makers deploy from the maker portal with a single click. No YAML, no agents, no ZIP files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fpipelines-hero.svg%3Fv%3D1826e63a" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fpipelines-hero.svg%3Fv%3D1826e63a" alt="Pipeline architecture from Dev through approval gates to Test and Production" width="954" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Pipelines in Power Platform Actually Are
&lt;/h2&gt;

&lt;p&gt;Pipelines are Microsoft's built-in CI/CD for Dataverse solutions. They are not Azure DevOps Pipelines. They are not GitHub Actions. They are a native feature inside Power Platform that handles solution export, validation, approval, and import across environments.&lt;/p&gt;

&lt;p&gt;The core idea: you configure a pipeline once (Dev to Test to Prod), and makers deploy from inside the maker portal by clicking a button. The system handles the export, validation, approval gates, connection mapping, and import. The maker never touches a ZIP file.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Not Azure DevOps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When someone says "Pipelines" in the Power Platform context, they mean the native deployment feature inside make.powerapps.com. This is completely separate from Azure DevOps Pipelines or GitHub Actions. Same word, different product.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;Every pipeline setup has three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline Host Environment.&lt;/strong&gt; A dedicated environment (usually production type) that stores pipeline configuration, deployment history, and solution artifacts. Microsoft provides a default platform host, or you can create a custom one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Development Environments.&lt;/strong&gt; Where makers build. These are linked to the pipeline as source environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target Environments.&lt;/strong&gt; Test, QA, Production. These are the stages in your pipeline, deployed to sequentially.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key constraint: you cannot skip stages. If your pipeline goes Dev to Test to Prod, you must deploy to Test first. The same solution artifact that passed through Test gets deployed to Prod. No re-export, no tampering, no "let me just make one more change before prod."&lt;/p&gt;

&lt;p&gt;This is intentional. It prevents customizations from bypassing your QA process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Your First Pipeline
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create or identify your host environment&lt;/strong&gt; Go to Power Platform admin center &amp;gt; Deployments &amp;gt; Pipelines. You can use the default Platform host or create a custom host environment. For most organizations, the Platform host is fine to start.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open the Deployment Pipeline Configuration app&lt;/strong&gt; In the host environment, open the Deployment Pipeline Configuration model-driven app. This is where you define pipelines, stages, and link environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a pipeline&lt;/strong&gt; Name it something meaningful like 'Core Business Apps Pipeline.' Add your stages in order: Dev &amp;gt; Test &amp;gt; Prod. Each stage links to a target environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Link development environments&lt;/strong&gt; Associate your development environments with the pipeline. Makers in these environments will see the pipeline when they open Solutions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure target environments as Managed Environments&lt;/strong&gt; All target environments must be Managed Environments. You can enable this manually or set it to auto-convert in the admin center under Deployments &amp;gt; Settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test with a simple solution&lt;/strong&gt; Create a small solution in your dev environment, navigate to Solutions, and look for the Pipelines option. Select Deploy, choose your target stage, and watch it work.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Managed Environments required&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As of February 2026, Microsoft auto-enables Managed Environments for any pipeline target that is not already managed. If you have not reviewed your Managed Environment settings, do it now. Check Power Platform admin center &amp;gt; Deployments &amp;gt; Settings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Approval Gates with Delegated Deployments
&lt;/h2&gt;

&lt;p&gt;Out of the box, any maker with access can deploy. That is fine for dev-to-test. For production, you want approval gates. Pipelines handle this through delegated deployments.&lt;/p&gt;

&lt;p&gt;When you enable delegated deployments on a pipeline stage, deployments require approval from an authorized identity before they proceed. The deployment runs under a service principal or a designated pipeline stage owner instead of the maker. This means makers can request deployments to production without having System Administrator access in the target environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;The pipeline extensibility model gives you three gated extension points. Think of them as stops on a train where you control whether it continues or not.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pre-export step.&lt;/strong&gt; Runs custom validation when a deployment request is submitted. The system will not export the solution from the dev environment until your logic marks this step complete. Use this for things like ensuring all flows are turned off or naming conventions are followed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Delegated deployment (approval).&lt;/strong&gt; The main approval gate. When enabled, the deployment pauses after export and waits for approval. You wire up a Power Automate cloud flow using the &lt;code&gt;OnApprovalStarted&lt;/code&gt; trigger. Inside that flow, you can add an approval action, send it to the right people, and then call the &lt;code&gt;UpdateApprovalStatus&lt;/code&gt; Dataverse action (20 = approved, 30 = rejected).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pre-deployment step.&lt;/strong&gt; An additional gate after approval but before the actual import. Useful for final sign-offs or automated checks.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All three can be used together or independently. For most organizations, the delegated deployment (approval gate) alone covers the core need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service Principal Setup
&lt;/h3&gt;

&lt;p&gt;For production deployments, use a service principal as the deploying identity:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an enterprise application (service principal) in Microsoft Entra ID&lt;/li&gt;
&lt;li&gt;Add it as a server-to-server user in the host and each target environment&lt;/li&gt;
&lt;li&gt;Assign Deployment Pipeline Administrator role in the host, System Administrator in targets&lt;/li&gt;
&lt;li&gt;On the pipeline stage, check "Is delegated deployment," select "Service Principal," and enter the Client ID&lt;/li&gt;
&lt;li&gt;Create a cloud flow in the host environment using the &lt;code&gt;OnApprovalStarted&lt;/code&gt; trigger&lt;/li&gt;
&lt;li&gt;Add your approval logic, then call &lt;code&gt;UpdateApprovalStatus&lt;/code&gt; using the service principal's connection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The service principal approach means flows deployed to production are owned by a service identity, not by "Karen from accounting who left six months ago." This solves the single biggest ALM headache in Power Platform.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Building a Power Platform governance practice? &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture patterns, ALM strategies, and governance deep dives every week.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Deployment Settings: Connection References and Environment Variables
&lt;/h2&gt;

&lt;p&gt;Connection references and environment variables hold different values per environment -- your dev SharePoint site isn't the same as production. See the &lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;environment strategy article&lt;/a&gt; for the full explanation and a worked example.&lt;/p&gt;

&lt;p&gt;Pipelines handle the mapping with deployment settings. During deployment, the system prompts for connection references and environment variables. For delegated deployments, admins can preconfigure these values using deployment settings files (JSON) generated with the Power Platform CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pac solution create-settings --solution-zip MySolution.zip --settings-file deploymentSettings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a JSON file with placeholders for connection IDs and environment variable values. Fill in the target environment specifics, and the pipeline uses them during import. No manual post-deployment configuration.&lt;/p&gt;

&lt;p&gt;Admins can even preconfigure certain connections that get used automatically, so makers don't need to provide connection details at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution Checker Validation
&lt;/h2&gt;

&lt;p&gt;Before a solution reaches your target environment, it runs through the solution checker. In Managed Environments, you control this with two settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Warn&lt;/strong&gt;: solution imports with a warning if there are critical issues, and an email goes to admins&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block&lt;/strong&gt;: solution import is canceled if there are critical issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The recommended configuration:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment Type&lt;/th&gt;
&lt;th&gt;Solution Checker&lt;/th&gt;
&lt;th&gt;Send Emails&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Default&lt;/td&gt;
&lt;td&gt;Block&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer&lt;/td&gt;
&lt;td&gt;Warn&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sandbox / Test&lt;/td&gt;
&lt;td&gt;Warn&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production&lt;/td&gt;
&lt;td&gt;Block&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This catches known anti-patterns: deprecated API usage, security issues, web resource problems, and accessibility violations. It does not, however, review the quality of your Power Automate flows. A flow with zero error handling, hardcoded URLs, and naming violations passes solution checker without a warning. That gap is real, and we will cover it in the &lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production" rel="noopener noreferrer"&gt;AI-powered flow review article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipelines vs Azure DevOps vs Manual
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Pipelines in Power Platform&lt;/th&gt;
&lt;th&gt;Azure DevOps / GitHub Actions&lt;/th&gt;
&lt;th&gt;Manual Export/Import&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup complexity&lt;/td&gt;
&lt;td&gt;Low - config in admin center&lt;/td&gt;
&lt;td&gt;High - YAML, agents, service connections&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Approval gates&lt;/td&gt;
&lt;td&gt;Built-in delegated deployments&lt;/td&gt;
&lt;td&gt;Release gates, environment approvals&lt;/td&gt;
&lt;td&gt;Email or Teams message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connection mapping&lt;/td&gt;
&lt;td&gt;Prompted during deployment&lt;/td&gt;
&lt;td&gt;Deployment settings JSON in pipeline&lt;/td&gt;
&lt;td&gt;Manual after import&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solution checker&lt;/td&gt;
&lt;td&gt;Automatic in Managed Environments&lt;/td&gt;
&lt;td&gt;Pipeline task (PAC CLI)&lt;/td&gt;
&lt;td&gt;Manual or skipped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Artifact storage&lt;/td&gt;
&lt;td&gt;Automatic in host environment&lt;/td&gt;
&lt;td&gt;Pipeline artifacts or repo&lt;/td&gt;
&lt;td&gt;Hopefully someone saved the ZIP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maker experience&lt;/td&gt;
&lt;td&gt;Click Deploy in maker portal&lt;/td&gt;
&lt;td&gt;Makers don't touch it (pro dev owned)&lt;/td&gt;
&lt;td&gt;Export ZIP, email it, import&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extensibility&lt;/td&gt;
&lt;td&gt;Power Automate triggers, Dataverse events&lt;/td&gt;
&lt;td&gt;Full YAML customization&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-tenant&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (manual)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Managed Environment licensing&lt;/td&gt;
&lt;td&gt;Azure DevOps subscription + licensing&lt;/td&gt;
&lt;td&gt;Free (but expensive in mistakes)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The sweet spot: use Pipelines for most deployments, and layer Azure DevOps or GitHub on top when you need source control integration, cross-tenant deployment, or complex branching strategies. Pipelines can be extended to integrate with both Azure DevOps and GitHub - they are not mutually exclusive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Default Deployment Pipelines for Environment Groups
&lt;/h2&gt;

&lt;p&gt;A newer capability: you can set a default deployment pipeline for environment groups. When a maker in a development environment tries to share their solution with users, the system prompts them to deploy through the pipeline first. This nudges makers toward the right process without blocking them outright.&lt;/p&gt;

&lt;p&gt;Combined with the admin deployment hub in the Power Platform admin center, admins get visibility into all deployments across the tenant, can approve or reject requests, retry failures, and manage pipeline configuration from a single place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do Power Platform Pipelines Replace Azure DevOps?
&lt;/h2&gt;

&lt;p&gt;Not entirely. Power Platform Pipelines cover the most common deployment scenarios without any external tooling, and they work well for teams that want maker-friendly CI/CD inside the platform. However, Azure DevOps and GitHub Actions still win for cross-tenant deployments, complex branching strategies, and full source control integration. Many enterprises use both together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Pipelines Do Not Cover
&lt;/h2&gt;

&lt;p&gt;Pipelines move solutions reliably. They validate against solution checker rules. They handle approvals and connection mapping. But they have a blind spot.&lt;/p&gt;

&lt;p&gt;Nobody reviews the actual content of the flows being promoted. The approval step is a rubber stamp if the approver does not open the solution and inspect every flow definition. And nobody does that for a solution with 15 flows.&lt;/p&gt;

&lt;p&gt;Solution checker catches structural anti-patterns. It does not catch business logic problems: missing error handling, hardcoded values that should be environment variables, unapproved connectors, inconsistent naming, or scope nesting so deep that nobody can debug it.&lt;/p&gt;

&lt;p&gt;That is the gap where AI-powered flow review fits in. We cover that in the &lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production" rel="noopener noreferrer"&gt;third article in this series&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Power Automate Governance - The Enterprise Playbook
&lt;/h2&gt;

&lt;p&gt;This article is part of a 10-part series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale/" rel="noopener noreferrer"&gt;Naming Conventions That Scale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;Environment Strategy - Dev Test Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm/" rel="noopener noreferrer"&gt;Solution-Aware Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see/" rel="noopener noreferrer"&gt;Flow Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-pipelines-moving-flows-from-dev-to-prod/" rel="noopener noreferrer"&gt;Pipelines - Dev to Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/coe-starter-kit-what-it-does-and-what-to-build-on-top/" rel="noopener noreferrer"&gt;CoE Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production/" rel="noopener noreferrer"&gt;AI-Powered Flow Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track/" rel="noopener noreferrer"&gt;Versioning and Source Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory/" rel="noopener noreferrer"&gt;The Governance Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-weekly-governance-digest-automated-health-report/" rel="noopener noreferrer"&gt;Weekly Governance Digest&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/power-platform-pipelines-moving-flows-from-dev-to-prod/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>devops</category>
      <category>powerautomate</category>
    </item>
    <item>
      <title>The Power Platform Governance Repo - Standards Reviews and Inventory in Git</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Mon, 14 Sep 2026 18:58:19 +0000</pubDate>
      <link>https://dev.to/az365ai/the-power-platform-governance-repo-standards-reviews-and-inventory-in-git-3g5m</link>
      <guid>https://dev.to/az365ai/the-power-platform-governance-repo-standards-reviews-and-inventory-in-git-3g5m</guid>
      <description>&lt;p&gt;A Power Platform governance repo is the missing single source of truth for every standard, checklist, and inventory report your platform team needs. Your governance documentation lives in three places. The naming conventions are in a Word doc on SharePoint. The flow inventory is in an Excel file on someone's OneDrive. The review checklist is in a Confluence page that hasn't been updated since 2024. The connector approval list is in someone's head.&lt;/p&gt;

&lt;p&gt;When a new team member asks "what are our standards?", nobody gives the same answer. Because there is no single answer. There are fragments scattered across tools, inboxes, and memory.&lt;/p&gt;

&lt;p&gt;Put it in git. One git repository. All governance artifacts. Version-controlled, searchable, and updated through pull requests like code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a single git repository for all Power Platform governance artifacts: naming conventions, review checklists, flow inventory CSVs, exported solutions, and AI review reports. Use pull requests for changes, automate inventory exports, and start with just two files in week one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fgovernance-repo-hero.svg%3Fv%3D54f2c153" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fgovernance-repo-hero.svg%3Fv%3D54f2c153" alt="Git repo folder structure with standards reviews inventory and solutions folders" width="642" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Power Platform Governance Repo?
&lt;/h2&gt;

&lt;p&gt;A Power Platform governance repo is a version-controlled git repository that centralizes all governance artifacts for your tenant. It holds naming standards, review checklists, connector approval lists, flow inventory data, exported solution files, and review reports in one searchable, auditable location with full change history through pull requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Git for Governance
&lt;/h2&gt;

&lt;p&gt;This isn't about being trendy with git. It's about solving three real problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 1: Nobody knows which version is current.&lt;/strong&gt; SharePoint has "Standards v3 FINAL revised (Alex comments).docx" and "Standards v4 draft.docx" in the same folder. Which one is active? With git, &lt;code&gt;main&lt;/code&gt; branch is always the current version. There's no ambiguity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 2: Changes happen silently.&lt;/strong&gt; Someone updates the naming convention in the Word doc. Nobody knows. No notification. No review. With git, every change is a pull request. The team sees the diff, reviews it, and approves it before it merges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 3: History disappears.&lt;/strong&gt; Why did we change the error handling standard last quarter? Who approved it? With git, &lt;code&gt;git log&lt;/code&gt; and &lt;code&gt;git blame&lt;/code&gt; tell you exactly when a line was added, who added it, and which PR it came from.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;SharePoint/Confluence&lt;/th&gt;
&lt;th&gt;Git Repository&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Single source of truth&lt;/td&gt;
&lt;td&gt;Multiple versions in multiple folders&lt;/td&gt;
&lt;td&gt;main branch is always current&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change tracking&lt;/td&gt;
&lt;td&gt;Document version history (hard to compare)&lt;/td&gt;
&lt;td&gt;Line-by-line diff on every change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review process&lt;/td&gt;
&lt;td&gt;Email someone and hope they read it&lt;/td&gt;
&lt;td&gt;Pull request with required reviewers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search&lt;/td&gt;
&lt;td&gt;File-level search, limited text search&lt;/td&gt;
&lt;td&gt;Full-text search across all files (grep)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automation&lt;/td&gt;
&lt;td&gt;Manual updates only&lt;/td&gt;
&lt;td&gt;Pipelines can auto-commit inventory data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Offline access&lt;/td&gt;
&lt;td&gt;Requires SharePoint access&lt;/td&gt;
&lt;td&gt;Local git clone, works offline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;History&lt;/td&gt;
&lt;td&gt;Who last modified the file&lt;/td&gt;
&lt;td&gt;Complete history of every line, every change, every reason&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Repository Structure
&lt;/h2&gt;

&lt;p&gt;Here's the structure that works. Not a theoretical ideal. This is the structure I set up for D365 implementation teams and what actually gets maintained.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;power-platform-governance/
  standards/
    naming-conventions.md
    error-handling-patterns.md
    review-checklist.md
    connector-approval-list.md
    environment-strategy.md
  inventory/
    flow-inventory.csv
    orphan-report.csv
    connector-audit.csv
  solutions/
    hr-evaluation/         (unpacked solution files via pac unpack)
    finance-approvals/
  reviews/
    hr-evaluation-v1.2-review.md   (AI-generated review)
    finance-approvals-v2.0-review.md
  reports/
    monthly-governance-report.md
  templates/
    flow-description-template.md
    new-flow-request-form.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's walk through each folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  standards/
&lt;/h3&gt;

&lt;p&gt;This is the core of the repo. Plain Markdown files that define how your team builds on Power Platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;naming-conventions.md&lt;/strong&gt; - Your flow, environment, solution, connection reference, and environment variable naming patterns. See the &lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale/" rel="noopener noreferrer"&gt;naming conventions article&lt;/a&gt; for the full standard -- this file is the org-specific version committed to your repo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;error-handling-patterns.md&lt;/strong&gt; - The standard error handling template. What scope structure to use. What to log. Where to send failure notifications. With actual examples from your environment, not generic guidance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;review-checklist.md&lt;/strong&gt; - What to check before promoting a flow. Connection references configured? Error handling present? Run-after configured on all actions? Variables named descriptively? This checklist is what reviewers use during PR reviews.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;connector-approval-list.md&lt;/strong&gt; - Which connectors are approved, restricted, or blocked. Updated when DLP policies change. Links to the DLP policy configuration in the admin center.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;environment-strategy.md&lt;/strong&gt; - What environments exist, what they're for, who has access, and the promotion path. Dev to test to production. Which environments are managed. Which allow maker access.&lt;/p&gt;

&lt;h3&gt;
  
  
  inventory/
&lt;/h3&gt;

&lt;p&gt;Data files that track what exists across your tenant. CSV format because it diffs well in git and opens in Excel when someone needs to filter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;flow-inventory.csv&lt;/strong&gt; - Every flow: name, owner, environment, solution, status, connectors used, last run date. This is the master list. Updated automatically (more on that below) or manually after each sprint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;orphan-report.csv&lt;/strong&gt; - Flows whose owners have left the org or been disabled. Updated weekly by automation or manual CoE export.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;connector-audit.csv&lt;/strong&gt; - Which connectors are in use, by which flows, in which environments. Cross-reference with the approval list in standards/.&lt;/p&gt;

&lt;h3&gt;
  
  
  solutions/
&lt;/h3&gt;

&lt;p&gt;Unpacked solution files from pac CLI. Each solution gets its own subfolder. This is where you track the actual flow definitions, entities, and configuration across versions. See &lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track" rel="noopener noreferrer"&gt;Power Automate Versioning and Source Control&lt;/a&gt; for the full export workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  reviews/
&lt;/h3&gt;

&lt;p&gt;AI-generated and human-written review reports for specific solution versions. When you review a solution before promotion, the findings go here. Naming convention: &lt;code&gt;{solution-name}-v{version}-review.md&lt;/code&gt;. These accumulate over time and become institutional knowledge.&lt;/p&gt;

&lt;h3&gt;
  
  
  reports/
&lt;/h3&gt;

&lt;p&gt;Periodic governance reports. Monthly summaries, quarterly health checks, annual audits. Markdown with data pulled from the inventory files.&lt;/p&gt;

&lt;h3&gt;
  
  
  templates/
&lt;/h3&gt;

&lt;p&gt;Reusable templates that makers and developers use when creating new flows or requesting new solutions. A description template ensures every flow has consistent documentation. A request form standardizes the intake process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Maintains What
&lt;/h2&gt;

&lt;p&gt;This is the critical question. A repo that nobody updates is worse than no repo because it creates false confidence. Here's the ownership model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Platform team (manual commits):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;standards/&lt;/code&gt; - Updated when policies change. Every change is a PR reviewed by the CoE lead or governance owner.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;templates/&lt;/code&gt; - Updated when standards evolve.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reviews/&lt;/code&gt; - Written or reviewed by a human after AI generates the first draft.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Automation (scheduled commits):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;inventory/&lt;/code&gt; - A scheduled pipeline exports data from Dataverse (CoE tables or admin connectors) and commits CSVs to the repo. Weekly or daily depending on org size.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;solutions/&lt;/code&gt; - A pre-deployment pipeline step runs &lt;code&gt;pac solution export&lt;/code&gt; and &lt;code&gt;pac solution unpack&lt;/code&gt;, committing the result before deploying. This captures the exact state of every deployment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reports/&lt;/code&gt; - Generated from inventory data by a pipeline or Power Automate flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;AI (generates drafts for human review):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;reviews/&lt;/code&gt; - AI reads flow JSON from &lt;code&gt;solutions/&lt;/code&gt;, generates review reports flagging issues, suggesting improvements. Human reviews and approves the PR.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reports/&lt;/code&gt; - AI summarizes inventory data into readable monthly reports. Human verifies accuracy.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Start with standards, automate inventory later&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You don't need the automation on day one. Create the repo, write your standards in Markdown, and commit them. That alone is a massive improvement over scattered Word docs. Add the automated inventory and solution exports once the team is comfortable with the repo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How It Connects to Other Tools
&lt;/h2&gt;

&lt;p&gt;The governance repo isn't a replacement for the CoE Starter Kit, DLP policies, or the admin center. It's the connective tissue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment pipelines.&lt;/strong&gt; Add a pre-deployment step that exports and unpacks the solution to the governance repo. Before deploying v1.3.0.0 to test, the pipeline commits the unpacked solution to &lt;code&gt;solutions/your-solution/&lt;/code&gt;. Now you have a git record of exactly what was deployed and when.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Center of Excellence (CoE) Starter Kit.&lt;/strong&gt; The CoE Kit collects inventory data in Dataverse tables. A scheduled flow or pipeline exports that data as CSV and commits it to &lt;code&gt;inventory/&lt;/code&gt;. The CoE remains the collection engine. Git becomes the archive and the diff engine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dataverse Git integration.&lt;/strong&gt; If you're using the built-in Git integration for dev environments, the governance repo is a separate concern. Dev repos track solution source code. The governance repo tracks standards, inventory, and reviews across all solutions. They complement each other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DLP policies.&lt;/strong&gt; Your &lt;code&gt;connector-approval-list.md&lt;/code&gt; in standards/ should mirror your actual DLP policies. When DLP policies change, update the Markdown. When the Markdown changes, someone should verify DLP policies match. The git history tells you when the standard changed and whether the policy was updated to match.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Want more governance patterns like this?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I share weekly breakdowns of Power Platform governance, automation architecture, and enterprise patterns. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow me on LinkedIn&lt;/a&gt; to get them in your feed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Setting Up the Initial Repo
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create the repository&lt;/strong&gt; Create a new repo in Azure DevOps or GitHub. Name it power-platform-governance or similar. Make it accessible to your platform team, solution architects, and governance reviewers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create the folder structure&lt;/strong&gt; Add the top-level folders: standards/, inventory/, solutions/, reviews/, reports/, templates/. Commit with a README.md that explains the purpose of each folder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write your naming conventions&lt;/strong&gt; Start with standards/naming-conventions.md. Document how your org names flows, environments, solutions, and connection references. Be specific - include examples. This is usually the most-referenced document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add the review checklist&lt;/strong&gt; Create standards/review-checklist.md. List every check that should happen before a flow is promoted. Error handling, connection references, variable naming, run-after configuration, documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export your current flow inventory&lt;/strong&gt; If you have the CoE Kit, export the flow inventory from Dataverse as CSV. If not, use the admin connectors or the admin center to compile a list. Save as inventory/flow-inventory.csv.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up branch protection&lt;/strong&gt; Protect the main branch. Require at least one reviewer for all pull requests to standards/. This ensures governance changes are reviewed, not silently edited.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Announce it to the team&lt;/strong&gt; Send the repo link to your platform team, solution architects, and makers. Walk them through the structure. Show them how to find the naming conventions and checklist. Make it part of onboarding.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Content of Each Standards File
&lt;/h2&gt;

&lt;p&gt;Let me be concrete about what goes in these files. Generic "follow Microsoft best practices" documents don't help anyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  naming-conventions.md
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Naming Conventions&lt;/span&gt;

&lt;span class="gu"&gt;## Cloud Flows&lt;/span&gt;
Pattern: {publisher-prefix}-{process}-{action}
Examples:
&lt;span class="p"&gt;-&lt;/span&gt; contoso-vendor-approval-send-notification
&lt;span class="p"&gt;-&lt;/span&gt; contoso-employee-onboarding-create-accounts
&lt;span class="p"&gt;-&lt;/span&gt; contoso-invoice-processing-extract-data

&lt;span class="gu"&gt;## Solution Names&lt;/span&gt;
Pattern: {BusinessUnit}{Domain}
Examples:
&lt;span class="p"&gt;-&lt;/span&gt; ContosoHROnboarding
&lt;span class="p"&gt;-&lt;/span&gt; ContosoFinanceApprovals

&lt;span class="gu"&gt;## Environment Variables&lt;/span&gt;
Pattern: {publisher-prefix}_{CATEGORY}_{Name}
Examples:
&lt;span class="p"&gt;-&lt;/span&gt; contoso_SMTP_SenderAddress
&lt;span class="p"&gt;-&lt;/span&gt; contoso_API_BaseUrl
&lt;span class="p"&gt;-&lt;/span&gt; contoso_FEATURE_EnableAutoApproval

&lt;span class="gu"&gt;## Connection References&lt;/span&gt;
Pattern: {publisher-prefix}_{ConnectorName}_{Purpose}
Examples:
&lt;span class="p"&gt;-&lt;/span&gt; contoso_SharePoint_HRDocuments
&lt;span class="p"&gt;-&lt;/span&gt; contoso_Outlook_Notifications
&lt;span class="p"&gt;-&lt;/span&gt; contoso_Dataverse_MainConnection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  review-checklist.md
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Flow Review Checklist&lt;/span&gt;

&lt;span class="gu"&gt;## Before Promotion to Test&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Flow is solution-aware (not a standalone flow)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Error handling: Try/Catch scope wraps all external calls
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Connection references used (no hardcoded connections)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Environment variables for all configurable values
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Variables have descriptive names (not var1, temp, x)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Run-after configured on all actions (not just "is successful")
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Flow description filled in (what it does, who owns it, what triggers it)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No premium connectors unless pre-approved
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Concurrency settings reviewed (parallel vs sequential)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Large data: pagination enabled where applicable
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No hardcoded URLs, emails, or IDs
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Tested with both success and failure scenarios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are living documents. When you find a new pattern that causes issues, add it to the checklist. When a naming collision happens, refine the naming convention. The git history shows the evolution of your standards over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoiding Over-Engineering
&lt;/h2&gt;

&lt;p&gt;The biggest risk isn't building too little. It's building too much on day one.&lt;/p&gt;

&lt;p&gt;One team I advised created a governance repo with 30 Markdown files, complex folder hierarchies, and automation pipelines before anyone has committed a single real standard. Two months later, the repo is abandoned because maintenance overhead exceeded the team's capacity.&lt;/p&gt;

&lt;p&gt;Start small:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Week 1:&lt;/strong&gt; &lt;code&gt;standards/naming-conventions.md&lt;/code&gt; and &lt;code&gt;standards/review-checklist.md&lt;/code&gt;. That's it. Two files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 2-4:&lt;/strong&gt; Use the checklist in actual reviews. Refine it based on what you find.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Month 2:&lt;/strong&gt; Add &lt;code&gt;inventory/flow-inventory.csv&lt;/code&gt; with a manual export. Add &lt;code&gt;standards/error-handling-patterns.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Month 3:&lt;/strong&gt; Automate the inventory export. Add solution exports for your most critical solutions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Month 4+:&lt;/strong&gt; Add AI reviews, monthly reports, and templates as the team matures.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each step should feel lightweight. If it feels heavy, you're going too fast.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Governance is a habit, not a project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The repo is the tool. The habit is using it. Block 30 minutes per sprint to review and update standards based on what the team learned. Make it a standing agenda item. Without the habit, the tool rots.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Making It Searchable
&lt;/h2&gt;

&lt;p&gt;One underrated benefit of Markdown in git: it's searchable from your IDE.&lt;/p&gt;

&lt;p&gt;Clone the governance repo. Open it in VS Code. &lt;code&gt;Ctrl+Shift+F&lt;/code&gt; to search across all files. Looking for the naming convention for environment variables? Search "Environment Variables." Want to know if a specific connector is approved? Search the connector name in &lt;code&gt;connector-approval-list.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Compare that to opening SharePoint, navigating to the right folder, opening a Word doc, and using &lt;code&gt;Ctrl+F&lt;/code&gt; inside the document. Multiply by 10 team members doing this 5 times a week.&lt;/p&gt;

&lt;p&gt;For teams that live in the terminal, &lt;code&gt;grep -r "approval" standards/&lt;/code&gt; finds every mention of "approval" across all standards files in under a second.&lt;/p&gt;




&lt;h2&gt;
  
  
  Power Automate Governance - The Enterprise Playbook
&lt;/h2&gt;

&lt;p&gt;This article is part of a 10-part series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale/" rel="noopener noreferrer"&gt;Naming Conventions That Scale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;Environment Strategy - Dev Test Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm/" rel="noopener noreferrer"&gt;Solution-Aware Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see/" rel="noopener noreferrer"&gt;Flow Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-pipelines-moving-flows-from-dev-to-prod/" rel="noopener noreferrer"&gt;Pipelines - Dev to Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/coe-starter-kit-what-it-does-and-what-to-build-on-top/" rel="noopener noreferrer"&gt;CoE Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production/" rel="noopener noreferrer"&gt;AI-Powered Flow Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track/" rel="noopener noreferrer"&gt;Versioning and Source Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory/" rel="noopener noreferrer"&gt;The Governance Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-weekly-governance-digest-automated-health-report/" rel="noopener noreferrer"&gt;Weekly Governance Digest&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>governance</category>
    </item>
    <item>
      <title>The Weekly Power Automate Governance Digest - Automated Platform Health</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Sun, 13 Sep 2026 17:10:00 +0000</pubDate>
      <link>https://dev.to/az365ai/the-weekly-power-automate-governance-digest-automated-platform-health-37mn</link>
      <guid>https://dev.to/az365ai/the-weekly-power-automate-governance-digest-automated-platform-health-37mn</guid>
      <description>&lt;p&gt;A Power Automate governance digest is the single most effective way to keep your platform team informed without relying on dashboards nobody opens. You built a Power BI dashboard for governance. It shows flow counts, failure rates, orphan status, connector usage. It looks great. Nobody opens it.&lt;/p&gt;

&lt;p&gt;This is the dashboard problem. Dashboards are pull-based. Someone has to remember to look. Someone has to navigate to the right report. Someone has to interpret the numbers and decide if action is needed. In practice, someone remembers to check the dashboard the week after something breaks. Then they forget again.&lt;/p&gt;

&lt;p&gt;Governance that depends on people remembering to look at a dashboard is governance that doesn't work.&lt;/p&gt;

&lt;p&gt;The fix: push the information. A weekly email that lands in the inbox of every platform admin, CoE lead, and IT manager. No login required. No navigation. No interpretation. Just a summary of what happened, what's broken, and what needs attention.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build a scheduled Power Automate flow that queries new flows, broken flows, orphaned flows, and policy violations weekly, then emails a structured summary to your governance team. Start with two sections (new flows and failures) and expand from there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fweekly-digest-hero.svg%3Fv%3Dda53adc4" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fweekly-digest-hero.svg%3Fv%3Dda53adc4" alt="Five data sources feeding into a scheduled flow producing a governance digest email"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Power Automate Governance Digest?
&lt;/h2&gt;

&lt;p&gt;A Power Automate governance digest is a scheduled email report that summarizes platform activity for a defined period, typically one week. It covers new flows, failed runs, orphaned flows, policy violations, and platform stats, all delivered to stakeholders without requiring them to log into any dashboard or admin center.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Push Beats Pull
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Dashboard (Pull)&lt;/th&gt;
&lt;th&gt;Email Digest (Push)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Requires action to see&lt;/td&gt;
&lt;td&gt;Yes - open browser, navigate, log in&lt;/td&gt;
&lt;td&gt;No - arrives in inbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regular cadence&lt;/td&gt;
&lt;td&gt;Only when someone remembers&lt;/td&gt;
&lt;td&gt;Automated weekly/monthly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context without effort&lt;/td&gt;
&lt;td&gt;Reader interprets raw charts&lt;/td&gt;
&lt;td&gt;Pre-interpreted with recommendations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reaches non-technical stakeholders&lt;/td&gt;
&lt;td&gt;Rarely - they don't know where to look&lt;/td&gt;
&lt;td&gt;Yes - email is universal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Creates accountability&lt;/td&gt;
&lt;td&gt;No paper trail of who saw what&lt;/td&gt;
&lt;td&gt;Delivered to a known audience&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works on mobile&lt;/td&gt;
&lt;td&gt;Requires Power BI app or browser&lt;/td&gt;
&lt;td&gt;Standard email client&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Dashboards still have value for deep dives and ad-hoc analysis. But for regular governance check-ins, email beats a dashboard every time. The goal is awareness, not analytics.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Goes in the Digest
&lt;/h2&gt;

&lt;p&gt;The digest covers everything a platform owner needs to know about the past week. Not raw data. Summarized, categorized, and prioritized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Section 1: New Flows Created This Week
&lt;/h3&gt;

&lt;p&gt;Every flow that was created in the past 7 days. For each flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flow name&lt;/li&gt;
&lt;li&gt;Creator (maker)&lt;/li&gt;
&lt;li&gt;Environment&lt;/li&gt;
&lt;li&gt;Solution (or "standalone" if not solution-aware)&lt;/li&gt;
&lt;li&gt;Connectors used&lt;/li&gt;
&lt;li&gt;Premium connector flag&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this matters: new flows that use premium connectors, access sensitive data, or run outside solutions need immediate attention. This section surfaces them before they become problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Section 2: Flows Modified This Week
&lt;/h3&gt;

&lt;p&gt;Flows that were updated or had new versions created. For each:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flow name&lt;/li&gt;
&lt;li&gt;Modified by&lt;/li&gt;
&lt;li&gt;Environment&lt;/li&gt;
&lt;li&gt;What changed (new version, modified actions - if available from audit log)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this matters: unauthorized changes to production flows are a governance failure. This section catches them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Section 3: Broken Flows
&lt;/h3&gt;

&lt;p&gt;Flows that had failed runs, were suspended by the platform, or were manually disabled. For each:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flow name&lt;/li&gt;
&lt;li&gt;Owner&lt;/li&gt;
&lt;li&gt;Environment&lt;/li&gt;
&lt;li&gt;Failure type (run failure, suspended, turned off)&lt;/li&gt;
&lt;li&gt;Last successful run&lt;/li&gt;
&lt;li&gt;Consecutive failure count&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this matters: a flow that fails silently is worse than no flow at all. Business processes depend on these flows running. This section is the early warning system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Section 4: Orphaned Flows
&lt;/h3&gt;

&lt;p&gt;Flows whose owners have been disabled or removed from the tenant. For each:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flow name&lt;/li&gt;
&lt;li&gt;Former owner&lt;/li&gt;
&lt;li&gt;Environment&lt;/li&gt;
&lt;li&gt;Last run date&lt;/li&gt;
&lt;li&gt;Impact assessment (is it still running? Is it critical?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this matters: orphaned flows are governance debt with interest. See the &lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see/" rel="noopener noreferrer"&gt;flow inventory article&lt;/a&gt; for the full orphan detection and remediation process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Section 5: Policy Violations
&lt;/h3&gt;

&lt;p&gt;Flows that violate DLP policies, use blocked connectors, or bypass approval requirements. For each:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flow name&lt;/li&gt;
&lt;li&gt;Violation type&lt;/li&gt;
&lt;li&gt;Owner&lt;/li&gt;
&lt;li&gt;Environment&lt;/li&gt;
&lt;li&gt;Severity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this matters: DLP policies block connector combinations at runtime. But makers can still build flows that will fail when they hit the policy boundary. This section catches flows that are configured to do things they're not allowed to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Section 6: Platform Stats
&lt;/h3&gt;

&lt;p&gt;High-level numbers for context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total flows (active, inactive, suspended)&lt;/li&gt;
&lt;li&gt;Solution-aware vs standalone flows&lt;/li&gt;
&lt;li&gt;Flows by environment&lt;/li&gt;
&lt;li&gt;Top 10 connectors by usage&lt;/li&gt;
&lt;li&gt;Flows created this month vs last month (trend)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Section 7: Upcoming Deadlines
&lt;/h3&gt;

&lt;p&gt;Review cycles, compliance dates, license renewals, environment refresh schedules. Anything time-sensitive that the governance team needs to act on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Sources
&lt;/h2&gt;

&lt;p&gt;You need data to build the digest. Here's where it comes from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Center of Excellence (CoE) Starter Kit Dataverse tables.&lt;/strong&gt; If you have the CoE Kit installed, this is the richest data source. The Kit's sync flows populate Dataverse tables with flow metadata, maker information, connector usage, and environment details. Query these tables with Dataverse connectors in Power Automate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Admin connectors.&lt;/strong&gt; The "Power Automate Management" and "Power Automate for Admins" connectors provide direct access to flow metadata across environments. No CoE Kit required. Less data than the CoE tables but sufficient for the core digest sections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Microsoft Purview audit logs.&lt;/strong&gt; For change tracking and compliance. Purview captures who created, modified, deleted, or shared a flow. Use the Office 365 Management Activity API or the audit log search to pull recent events.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data Source&lt;/th&gt;
&lt;th&gt;Data Available&lt;/th&gt;
&lt;th&gt;Setup Effort&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CoE Starter Kit&lt;/td&gt;
&lt;td&gt;Full inventory, maker data, connectors, environments, app usage&lt;/td&gt;
&lt;td&gt;High (install and configure CoE)&lt;/td&gt;
&lt;td&gt;Orgs with 100+ flows that need deep visibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin connectors&lt;/td&gt;
&lt;td&gt;Flow metadata, run history, environment list&lt;/td&gt;
&lt;td&gt;Low (just add the connectors)&lt;/td&gt;
&lt;td&gt;Smaller orgs or quick-start without CoE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Purview audit logs&lt;/td&gt;
&lt;td&gt;Create/modify/delete events, user activity&lt;/td&gt;
&lt;td&gt;Medium (API setup, permissions)&lt;/td&gt;
&lt;td&gt;Compliance-focused orgs, change auditing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most teams start with admin connectors and add CoE data later. Don't wait for a perfect CoE installation to start sending digests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Digest Flow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a scheduled cloud flow&lt;/strong&gt; Trigger: Recurrence. Set to run every Monday at 8 AM (or whatever day works for your team). Run it in a managed environment with appropriate admin permissions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query new flows created in the past 7 days&lt;/strong&gt; Use the Power Automate for Admins connector - List Flows as Admin. Filter by created date &amp;gt;= 7 days ago. For each flow, capture: name, creator, environment, connectors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query failed flow runs&lt;/strong&gt; Use the Power Automate Management connector - List Flow Runs. Filter for failed runs in the past 7 days. Group by flow to get failure counts and last success date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query orphaned flows&lt;/strong&gt; Cross-reference flow owners with Azure AD (Entra ID). If the owner's account is disabled or deleted, flag the flow. Use the Office 365 Users connector to check account status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check DLP policy compliance&lt;/strong&gt; Compare each flow's connector list against your approved connector list. Flag any flow using restricted or blocked connectors. Reference your governance repo's connector-approval-list.md.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compile the HTML email&lt;/strong&gt; Build an HTML body with sections for each category. Use tables for structured data. Color-code severity: red for critical (orphans, policy violations), yellow for warnings (failures), green for informational (new flows, stats).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send to the governance team&lt;/strong&gt; Use the Outlook connector to send the email to your distribution group: platform admins, CoE lead, IT manager. Include a link to the governance repo for standards reference.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Keep the first version simple&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don't try to build all 7 sections in the first iteration. Start with new flows and broken flows. Those two sections alone provide more visibility than most teams have. Add orphan detection, policy checks, and stats in later versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want more governance patterns like this?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I share weekly breakdowns of Power Platform governance, automation architecture, and enterprise patterns. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow me on LinkedIn&lt;/a&gt; to get them in your feed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Email Format
&lt;/h2&gt;

&lt;p&gt;Structure matters. A wall of text gets skimmed and closed. A well-structured email gets read and acted on.&lt;/p&gt;

&lt;p&gt;Here's the format that works. Example digest body. The names and counts below are illustrative, not from a real tenant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Subject: Power Platform Weekly Digest - Mar 10-17, 2026

SUMMARY
- 4 new flows created (1 uses premium connector)
- 2 flows with repeated failures
- 1 orphaned flow (owner left org Feb 28)
- 0 policy violations

---

NEW FLOWS (4)
| Name | Creator | Environment | Connectors | Flag |
| Vendor invoice OCR | jsmith | Production | AI Builder, SharePoint | Premium |
| Team standup reminder | mjones | Dev | Outlook | - |
| Contract renewal alert | klee | Production | Dataverse, Outlook | - |
| Data export to SFTP | jsmith | Production | SFTP, Dataverse | Review needed |

---

BROKEN FLOWS (2)
| Name | Owner | Environment | Failures (7d) | Last Success |
| Nightly data sync | agarcia | Production | 14 | Mar 8 |
| Customer feedback digest | rchen | Test | 3 | Mar 14 |

---

ORPHANED FLOWS (1)
| Name | Former Owner | Environment | Last Run | Status |
| Budget approval routing | tlee (disabled Feb 28) | Production | Mar 15 | Still running |

---

PLATFORM STATS
- Total flows: 187 (142 active, 28 inactive, 17 suspended)
- Solution-aware: 134 (72%)
- Standalone: 53 (28%)
- New this month: 12
- Trend: +8% vs last month
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The summary at the top is critical. A busy IT manager reads the first 4 lines and knows whether to keep reading. "0 policy violations, 1 orphan" takes 3 seconds to process. If something is red, they dig into the details below.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Enhancement
&lt;/h2&gt;

&lt;p&gt;Raw data is useful. Interpreted data is actionable.&lt;/p&gt;

&lt;p&gt;Feed the digest data to an AI before sending it. Ask for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A plain-English summary of the platform's health this week&lt;/li&gt;
&lt;li&gt;Risk flags with severity ratings&lt;/li&gt;
&lt;li&gt;Specific recommendations for each issue&lt;/li&gt;
&lt;li&gt;Trend analysis compared to the previous digest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of just listing "Nightly data sync - 14 failures," the AI-enhanced version says: "The Nightly data sync flow in Production has failed 14 consecutive times since March 8. This flow is owned by agarcia and processes customer records for the data warehouse. Recommendation: investigate immediately. The data warehouse is likely 9 days behind."&lt;/p&gt;

&lt;p&gt;That's the difference between information and intelligence.&lt;/p&gt;

&lt;p&gt;You can implement this by adding a step in your digest flow that calls Azure OpenAI (or any AI endpoint) with the compiled data and a prompt asking for a summary with recommendations. Append the AI summary to the top of the email, above the raw data sections.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Review AI summaries before sending&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you add AI-generated summaries, review them for the first few weeks. AI can misinterpret data, exaggerate risks, or make incorrect recommendations. Set up the flow to send a draft to the CoE lead first, then forward the approved version to the broader team. Once you trust the output, you can automate the full send.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Escalation Triggers
&lt;/h2&gt;

&lt;p&gt;Some issues shouldn't wait for the weekly digest. Set up real-time alerts for critical governance events:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production flow owned by departed employee.&lt;/strong&gt; The moment HR disables an account, check if that user owns any production flows. If yes, alert the platform team immediately. Don't wait until Monday.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flow using blocked connector.&lt;/strong&gt; If a new flow or flow modification introduces a connector that's on the blocked list, flag it the same day. DLP policies will block it at runtime anyway, but the maker needs to know before they waste more time building on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;High-impact flow failure.&lt;/strong&gt; Define which flows are business-critical (revenue-impacting, compliance-required, customer-facing). If any of these fail, send an immediate notification. Don't let them accumulate until the weekly digest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spike in new flows.&lt;/strong&gt; If the number of new flows this week is 3x the average, something is happening. Maybe a new team started building on Power Platform without going through the intake process. Flag it for review.&lt;/p&gt;

&lt;p&gt;These escalation triggers run as separate flows, not part of the digest. The digest is for routine awareness. Escalations are for things that can't wait.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cadence and Audience
&lt;/h2&gt;

&lt;p&gt;Not every org needs a weekly digest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;100+ flows, multiple teams:&lt;/strong&gt; Weekly digest. Enough activity to justify the cadence. Send to platform admins, CoE lead, IT manager.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;30-100 flows, small team:&lt;/strong&gt; Biweekly. Less noise, still useful. Send to the platform owner and IT lead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Under 30 flows:&lt;/strong&gt; Monthly. Or even quarterly. At this scale, you might know every flow by name. The digest is more of a health check than a monitoring tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who gets it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Platform admins (required). They act on the issues.&lt;/li&gt;
&lt;li&gt;CoE lead (required). They track trends and set policy.&lt;/li&gt;
&lt;li&gt;IT manager (recommended). They need visibility without logging into the admin center.&lt;/li&gt;
&lt;li&gt;Solution architects (optional). They benefit from seeing what's being built and how.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't send it to every maker. The audience is governance stakeholders, not the entire organization. Makers get feedback through the review process, not the digest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to the Governance Repo
&lt;/h2&gt;

&lt;p&gt;The digest becomes more powerful when it links to your governance repo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New flow uses a connector? Link to &lt;code&gt;standards/connector-approval-list.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Flow fails a review check? Link to &lt;code&gt;standards/review-checklist.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Orphaned flow detected? Link to &lt;code&gt;standards/environment-strategy.md&lt;/code&gt; for the escalation procedure.&lt;/li&gt;
&lt;li&gt;AI review generated? Link to the review report in &lt;code&gt;reviews/&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The email is the notification. The repo is the documentation. Together, they form a governance loop: detect issues (digest), reference standards (repo), take action, update standards if needed (PR to repo).&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory" rel="noopener noreferrer"&gt;The Power Platform Governance Repo&lt;/a&gt; for the full repo setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started in One Afternoon
&lt;/h2&gt;

&lt;p&gt;You don't need all 7 sections to start. Here's the minimum viable digest:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a scheduled flow&lt;/strong&gt; (Recurrence - weekly)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query new flows&lt;/strong&gt; created in the past 7 days (Power Automate for Admins - List Flows as Admin)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query failed runs&lt;/strong&gt; (Power Automate Management - List Flow Runs, filter status = Failed)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Format a simple HTML email&lt;/strong&gt; with two tables: new flows and failures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send to yourself&lt;/strong&gt; first. Review it. Adjust the queries. Then add your team.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's 2-3 hours of work for a flow that runs forever. Every Monday, your inbox tells you what happened on your platform. No dashboards to check. No reports to pull.&lt;/p&gt;

&lt;p&gt;From there, add orphan detection in week 2, policy checks in week 3, and AI summaries in month 2. Each addition is incremental. Each one makes the digest more useful.&lt;/p&gt;




&lt;h2&gt;
  
  
  Power Automate Governance - The Enterprise Playbook
&lt;/h2&gt;

&lt;p&gt;This article is part of a 10-part series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale/" rel="noopener noreferrer"&gt;Naming Conventions That Scale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod/" rel="noopener noreferrer"&gt;Environment Strategy - Dev Test Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm/" rel="noopener noreferrer"&gt;Solution-Aware Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see/" rel="noopener noreferrer"&gt;Flow Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-pipelines-moving-flows-from-dev-to-prod/" rel="noopener noreferrer"&gt;Pipelines - Dev to Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/coe-starter-kit-what-it-does-and-what-to-build-on-top/" rel="noopener noreferrer"&gt;CoE Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production/" rel="noopener noreferrer"&gt;AI-Powered Flow Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track/" rel="noopener noreferrer"&gt;Versioning and Source Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory/" rel="noopener noreferrer"&gt;The Governance Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-weekly-governance-digest-automated-health-report/" rel="noopener noreferrer"&gt;Weekly Governance Digest&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/power-automate-weekly-governance-digest-automated-health-report/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>governance</category>
    </item>
    <item>
      <title>Notification Architecture That Cannot Break Your Business Logic</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Sat, 12 Sep 2026 16:40:08 +0000</pubDate>
      <link>https://dev.to/az365ai/notification-architecture-that-cannot-break-your-business-logic-38i1</link>
      <guid>https://dev.to/az365ai/notification-architecture-that-cannot-break-your-business-logic-38i1</guid>
      <description>&lt;p&gt;A signing workflow processes evaluations through a multi-step chain. When a Power Automate notification flow fails, business impact is zero. When a business flow fails, the chain stops. These two outcomes are possible only because notification flows and business flows share nothing. Not a trigger. Not a variable. Not a solution import cycle.&lt;/p&gt;

&lt;p&gt;Every notification flow in this pattern follows one rule: read Dataverse, send email, never write back. That rule is non-negotiable. It is the single architectural decision that makes the entire notification layer disposable without risk to the business.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Separate Power Automate notification flows from business logic entirely. Notification flows should only read Dataverse and send emails. Use daily digests instead of real-time triggers, one flow per email template, and boolean tracking flags for idempotent delivery.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fnotification-separation-architecture.svg%3Fv%3Dc477739f" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Fnotification-separation-architecture.svg%3Fv%3Dc477739f" alt="Two-zone architecture showing business flows separated from notification flows with no coupling" width="894" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Temptation
&lt;/h2&gt;

&lt;p&gt;Every maker hits this moment. A flow creates an evaluation record, assigns ownership, configures access teams, and advances the signing chain. At the end of that sequence, the natural thought is: "I should send an email to let the signer know." So a SendEmailV2 action goes at the bottom of the flow.&lt;/p&gt;

&lt;p&gt;It works. The signer gets the email. Ship it.&lt;/p&gt;

&lt;p&gt;Here is what just happened. Notification logic was coupled to business logic. If the Outlook connector throttles, the business flow retries. If the email action throws an error, the flow's error handling must now account for a notification failure in the middle of a signing chain operation. Editing the email template means editing a flow that manages business-critical state transitions. One wrong click breaks the signing chain, not the email.&lt;/p&gt;

&lt;p&gt;This is how it starts. One email action inside one business flow. Then another. Then a condition block: "If status = Rejected, send this email. If status = Approved, send that one." The business flow grows. The email logic grows inside it. Testing the email means running the entire business flow. Disabling the email means disabling the business flow. The two concerns are permanently fused.&lt;/p&gt;

&lt;p&gt;This pattern shows up across many production environments. It always ends the same way: a notification change breaks business logic, and nobody understands why the signing chain stopped advancing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Separation Principle
&lt;/h2&gt;

&lt;p&gt;Notification flows never write to Dataverse. Full stop.&lt;/p&gt;

&lt;p&gt;This is not a best-practice recommendation. It is a structural constraint. Business flows (REV, EVL, STP series in the &lt;a href="https://az365.ai/blog/tag-based-flow-architecture-power-automate" rel="noopener noreferrer"&gt;tag-based architecture&lt;/a&gt;) handle all write operations: creating records, assigning ownership, managing access teams, advancing the signing chain. Notification flows (NTF series) handle one thing: querying Dataverse and sending emails.&lt;/p&gt;

&lt;p&gt;The separation happens at the flow level, not at the action level. There is no shared flow that branches between "do business logic" and "send notification." Each concern lives in its own flow with its own trigger, its own run history, its own deployment cycle. To visualize this separation, &lt;a href="https://az365.ai/blog/architecture-diagrams-with-draw-io-mcp-and-claude" rel="noopener noreferrer"&gt;architecture diagrams generated from text descriptions&lt;/a&gt; make the boundary obvious: business flows on one side, notification flows on the other, a wall between them.&lt;/p&gt;

&lt;p&gt;What this means in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A notification failure never breaks the signing chain.&lt;/strong&gt; The business flows do not know notification flows exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notification flows can be disabled without risk.&lt;/strong&gt; The product owner can turn off "Signer Heads-Up" emails (NTF04) without affecting a single business operation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing is independent.&lt;/strong&gt; Notification flows are tested by verifying email content and recipient logic. There is no risk of accidentally advancing signing steps or reassigning record ownership.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment is independent.&lt;/strong&gt; Notification flows ship in their own &lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm" rel="noopener noreferrer"&gt;solution import cycle&lt;/a&gt;. Email wording can be updated without touching the business solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The one exception to 'never write'&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When boolean notification tracking flags (covered below) are added, the notification flow writes exactly one field per record: setting &lt;code&gt;app_notified_assigned&lt;/code&gt; from &lt;code&gt;false&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;. This is still separated. A tracking flag failure cannot break the signing chain. It can only cause a duplicate email on the next run.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Should Notifications Be Real-Time or Daily Digest?
&lt;/h2&gt;

&lt;p&gt;In most cases, daily digests win. Real-time notifications cause email floods during bulk operations, training users to ignore them entirely. Batching notifications into a single daily email per recipient and reserving real-time delivery only for events that are rare, urgent, and triggered by a deliberate human action gives a better recipient experience.&lt;/p&gt;

&lt;p&gt;Here is the scenario that argues against real-time delivery.&lt;/p&gt;

&lt;p&gt;A product owner opens a review cycle for an entire department. The review-cycle flow fires and bulk-creates dozens of evaluation records, one for each employee. Each creation triggers the evaluator-assignment flow, the access-team flow, and the signing-step setup flow. The entire batch completes in under two minutes.&lt;/p&gt;

&lt;p&gt;With real-time notifications, dozens of "Form Assigned" emails fire within seconds. A division director supervising eight employees receives eight separate emails. A senior manager overseeing three team leads receives notifications for every indirect report. The email flood trains users to ignore notification emails entirely, which is the opposite of what notifications are supposed to do.&lt;/p&gt;

&lt;p&gt;Microsoft's own guidance warns about this. The &lt;a href="https://learn.microsoft.com/power-platform/architecture/key-concepts/integration-patterns/patterns#event-driven-pattern" rel="noopener noreferrer"&gt;event-driven pattern documentation&lt;/a&gt; explicitly calls out the need to "prevent multiple updates from causing rapid, repeated notifications" and to "prepare a mitigation plan for unexpected spikes in event frequency."&lt;/p&gt;

&lt;p&gt;The daily digest is the mitigation plan.&lt;/p&gt;

&lt;p&gt;At a fixed time on weekdays, each notification flow runs on a &lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod" rel="noopener noreferrer"&gt;scheduled recurrence&lt;/a&gt;. It queries Dataverse for records modified in the last 24 hours, groups results by recipient, and sends one email per person. A supervisor with 8 new assignments receives a single email: "You have 8 new forms assigned" with a summary table and deep links to each record. One email. Scannable. Actionable.&lt;/p&gt;

&lt;p&gt;The flow uses FetchXML to query and sort results by recipient, then iterates with recipient change detection to build per-person HTML bodies using Select and Create HTML Table. Every email is sent from a shared mailbox using SharedMailboxSendEmailV2, not SendEmailV2. Microsoft &lt;a href="https://learn.microsoft.com/power-automate/guidance/planning/formalizing-messages-alerts" rel="noopener noreferrer"&gt;recommends shared senders&lt;/a&gt; over personal accounts for formalized notifications. The recipient sees the application name as the sender, not a developer's personal email. For details on how the FetchXML queries work, see &lt;a href="https://az365.ai/blog/fetchxml-power-automate-odata-filter-alternative" rel="noopener noreferrer"&gt;FetchXML in Power Automate&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Exception: Rejection
&lt;/h2&gt;

&lt;p&gt;Not every notification belongs in a digest.&lt;/p&gt;

&lt;p&gt;When a signer rejects an evaluation, three things are true: it is rare (typically one at a time, never in bulk), it is urgent (the author needs to revise immediately), and it is always a deliberate human action. A person clicked "Reject," typed a reason, and submitted. This is not a bulk operation that floods inboxes.&lt;/p&gt;

&lt;p&gt;NTF05 and NTF06 are the only event-driven flows in the notification layer. NTF05 notifies the author that their form was rejected. NTF06 notifies all previous signers whose signatures are now invalidated by the rejection. Both trigger on the signing step status changing to "Rejected" and fire immediately.&lt;/p&gt;

&lt;p&gt;This exception is not a crack in the architecture. It is proof that the architecture is honest. Blanket rules like "always batch notifications" ignore reality. The right rule is: batch by default, real-time only when the event is rare, urgent, and human-initiated.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Flow Per Email Template
&lt;/h2&gt;

&lt;p&gt;The pattern uses one notification flow per email type, not a monolithic flow with conditional branches.&lt;/p&gt;

&lt;p&gt;Each flow sends exactly one type of email. NTF01 sends "Form Assigned" digests. NTF02 sends "Ready for Signature" digests. NTF05 sends rejection alerts. No flow contains conditional logic that selects between email templates based on input.&lt;/p&gt;

&lt;p&gt;Why this matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring.&lt;/strong&gt; Each flow's run history shows exactly one email type. If "Ready for Signature" emails stop working, the right flow to inspect is NTF02. There is no scrolling through a monolithic flow's run history trying to filter by which branch executed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging.&lt;/strong&gt; A failed run points to a specific notification scenario. The flow name tells the problem domain before opening it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Management.&lt;/strong&gt; When the product owner wants to disable "Signer Heads-Up" notifications during a pilot, NTF04 is turned off. Nothing else changes. There is no risk of a condition block accidentally suppressing a different email type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Naming.&lt;/strong&gt; The &lt;a href="https://az365.ai/blog/tag-based-flow-architecture-power-automate" rel="noopener noreferrer"&gt;tag-based naming convention&lt;/a&gt; makes every flow discoverable: &lt;code&gt;&amp;lt;App&amp;gt; | [NTF04] Signer Heads-Up - Daily Digest&lt;/code&gt;. The tag tells you what it does before you open it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many small flows are easier to build, test, monitor, and maintain than one large flow with many branches. The monolithic approach fails the moment two email types share a partial query and someone edits the shared part without understanding both branches.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Designing notification flows?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for Power Automate architecture patterns and notification design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Notification Tracking
&lt;/h2&gt;

&lt;p&gt;Every scheduled notification flow needs to answer one question: which records have already been notified about?&lt;/p&gt;

&lt;h3&gt;
  
  
  V1: 24-Hour Lookback (Simple, Fragile)
&lt;/h3&gt;

&lt;p&gt;The simplest implementation uses &lt;code&gt;modifiedon&lt;/code&gt; with a &lt;code&gt;last-x-hours 24&lt;/code&gt; FetchXML filter. The flow runs at 8:00 AM, queries for records modified in the last 24 hours, and sends digest emails. Simple to build. No schema changes required.&lt;/p&gt;

&lt;p&gt;The weakness is obvious. If the flow fails at 8:00 AM Tuesday and nobody notices until Wednesday, the Tuesday records fall outside the 24-hour window. They are never notified. Microsoft &lt;a href="https://learn.microsoft.com/troubleshoot/power-platform/power-automate/flow-run-issues/triggers-troubleshoot#trigger-fires-for-old-events" rel="noopener noreferrer"&gt;documents this behavior&lt;/a&gt;: polling triggers do not retroactively catch missed windows when restarted.&lt;/p&gt;

&lt;p&gt;For a launch with monitoring in place, this is acceptable. It is not resilient.&lt;/p&gt;

&lt;h3&gt;
  
  
  V2: Boolean Tracking Flags (Idempotent, Resilient)
&lt;/h3&gt;

&lt;p&gt;The improved pattern adds boolean fields to each notifiable table. The illustrative schema below uses an &lt;code&gt;app_*&lt;/code&gt; placeholder prefix.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table&lt;/th&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;app_personnelevaluation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_notified_assigned&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Author notified of assignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;app_personnelevaluation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_notified_complete&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Author notified of completion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;app_evaluationsigningstep&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_notified_awaiting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Signer notified of activation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;app_evaluationsigningstep&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_notified_created&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Signer notified of assignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;app_personnelreviewcycle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_notified_launched&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Participants notified of launch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;app_personnelreviewcycle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_notified_closed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Participants notified of close&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The flow queries for records where the flag is &lt;code&gt;false&lt;/code&gt;, sends the notification, then sets the flag to &lt;code&gt;true&lt;/code&gt;. If the flow fails mid-run, the unprocessed records still have &lt;code&gt;false&lt;/code&gt; flags. The next run picks them up. No gap. No missed notifications. Microsoft &lt;a href="https://learn.microsoft.com/troubleshoot/power-platform/power-automate/flow-run-issues/triggers-troubleshoot#my-flow-is-triggered-multiple-times-or-some-of-my-actions-run-multiple-times" rel="noopener noreferrer"&gt;recommends idempotent design&lt;/a&gt; exactly for this reason.&lt;/p&gt;

&lt;p&gt;The worst case with boolean flags is a duplicate email: the flow sends the email, crashes before setting the flag, and the next run sends it again. A duplicate email is inconvenient. A missed notification during a performance review cycle is a compliance problem.&lt;/p&gt;

&lt;p&gt;Build v1 for launch. Plan v2 from day one. Do not over-engineer the first release, but do not pretend the weakness does not exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample Flow Inventory
&lt;/h2&gt;

&lt;p&gt;Here is a sample notification layer for a hypothetical performance management application, illustrating the pattern. The point is structure, not the specific flow set.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheduled Flows (Daily, Weekdays)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Flow Name&lt;/th&gt;
&lt;th&gt;Table Queried&lt;/th&gt;
&lt;th&gt;Recipient&lt;/th&gt;
&lt;th&gt;Priority&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NTF01&lt;/td&gt;
&lt;td&gt;Form Assigned&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_personnelevaluation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Author&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF02&lt;/td&gt;
&lt;td&gt;Ready for Signature&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_evaluationsigningstep&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Signer (non-self)&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF07&lt;/td&gt;
&lt;td&gt;Evaluation Complete&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_personnelevaluation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Author&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF10&lt;/td&gt;
&lt;td&gt;Author Reminder&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_personnelevaluation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Author&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF11&lt;/td&gt;
&lt;td&gt;Author Past Due&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_personnelevaluation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Author&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF12&lt;/td&gt;
&lt;td&gt;Supervisor Escalation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_personnelevaluation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Author's supervisor&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF08&lt;/td&gt;
&lt;td&gt;Cycle Launched&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_personnelreviewcycle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All participants&lt;/td&gt;
&lt;td&gt;P3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF09&lt;/td&gt;
&lt;td&gt;Cycle Closed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_personnelreviewcycle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All participants&lt;/td&gt;
&lt;td&gt;P3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Real-Time Flows (Event-Driven, Immediate)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Flow Name&lt;/th&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;Recipient&lt;/th&gt;
&lt;th&gt;Priority&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NTF05&lt;/td&gt;
&lt;td&gt;Rejection to Author&lt;/td&gt;
&lt;td&gt;Step status changed to Rejected&lt;/td&gt;
&lt;td&gt;Author&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF06&lt;/td&gt;
&lt;td&gt;Rejection to Previous Signers&lt;/td&gt;
&lt;td&gt;Step status changed to Rejected&lt;/td&gt;
&lt;td&gt;Previous signers&lt;/td&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Priority Tiers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;P1&lt;/strong&gt; flows are must-have for go-live. Core signing workflow notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;P2&lt;/strong&gt; flows are important but informational. They can follow shortly after go-live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;P3&lt;/strong&gt; flows are nice-to-have. Cycle-level broadcasts can be deferred without impacting individual evaluations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The NTF tag prefix is deliberately simple. It accepts a channel suffix (NTF-EMAIL, NTF-INAPP, NTF-TEAMS) when multi-channel delivery is added. The naming convention is ready before the channels exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embedded vs Separated
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Embedded (SendEmail inside business flow)&lt;/th&gt;
&lt;th&gt;Separated (Independent NTF flows)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Failure impact&lt;/td&gt;
&lt;td&gt;Notification failure can break business flow execution. If SendEmail throws an error mid-flow, the signing chain may halt.&lt;/td&gt;
&lt;td&gt;Notification failure has zero business impact. The signing chain continues regardless.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing&lt;/td&gt;
&lt;td&gt;Must test notifications and business logic together. Email testing triggers real state changes.&lt;/td&gt;
&lt;td&gt;Test notifications independently. No risk of advancing signing steps or reassigning ownership.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Business flows and notifications deploy together. A template change requires retesting the signing chain.&lt;/td&gt;
&lt;td&gt;Notification flows ship in their own solution. Update email wording without touching business flows.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bulk operations&lt;/td&gt;
&lt;td&gt;A single bulk operation creating dozens of records triggers an embedded email per record. Inboxes flood.&lt;/td&gt;
&lt;td&gt;Scheduled digest batches all records into one email per recipient at the next run.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring&lt;/td&gt;
&lt;td&gt;Run history mixes business actions and email sends. Hard to isolate notification failures.&lt;/td&gt;
&lt;td&gt;Each NTF flow shows exactly one notification type. Failure points to a specific scenario.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disabling&lt;/td&gt;
&lt;td&gt;Cannot disable notifications without disabling the business flow.&lt;/td&gt;
&lt;td&gt;Disable any single notification type without affecting business operations.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every dimension favors separation. The only argument for embedding is convenience: it is faster to add one SendEmail action than to build a separate flow. That convenience evaporates the moment you need to debug, deploy, or disable independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes This Work
&lt;/h2&gt;

&lt;p&gt;Three &lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod" rel="noopener noreferrer"&gt;environment variables&lt;/a&gt; drive notification flows in this pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app_EnvironmentURL&lt;/code&gt; for the base URL of deep links (changes per environment)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app_NotificationsMailbox&lt;/code&gt; for the shared mailbox address used by SharedMailboxSendEmailV2&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app_AppID&lt;/code&gt; for the Model-Driven App identifier used in record deep links&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every email includes a direct link to the relevant record: &lt;code&gt;{EnvironmentURL}/main.aspx?etn=app_personnelevaluation&amp;amp;id={recordId}&amp;amp;pagetype=entityrecord&amp;amp;appid={AppID}&amp;amp;forceUCI=1&lt;/code&gt;. The &lt;code&gt;appid&lt;/code&gt; parameter opens the record in the correct app. The &lt;code&gt;forceUCI=1&lt;/code&gt; parameter forces the Unified Client Interface. The user clicks the link and lands on the exact record that needs attention.&lt;/p&gt;

&lt;p&gt;The shared mailbox is critical. Microsoft &lt;a href="https://learn.microsoft.com/power-automate/guidance/planning/formalizing-messages-alerts" rel="noopener noreferrer"&gt;explicitly recommends&lt;/a&gt; sending formalized notifications from a shared sender, not from the flow owner's personal email. Recipients know the message came from automation, and IT can manage the mailbox independently of any individual user's account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Separated or Build Twice
&lt;/h2&gt;

&lt;p&gt;Most teams build notifications embedded in business flows the first time, then rebuild them separated the second time. The separation principle is the kind of decision you only need to learn once.&lt;/p&gt;

&lt;p&gt;Notification flows read. Business flows write. The two share nothing. When one breaks, the other continues. When one deploys, the other is untouched. That is the architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Spec-Driven Power Platform Series
&lt;/h2&gt;

&lt;p&gt;This article is part of a series on building Power Automate solutions with specs, governance, and AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/tag-based-flow-architecture-power-automate" rel="noopener noreferrer"&gt;Tag-Based Flow Architecture&lt;/a&gt; - How 3-letter prefixes make a flow set manageable&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/spec-first-power-automate-development" rel="noopener noreferrer"&gt;Spec-First Development&lt;/a&gt; - Why specs should exist before the designer opens&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/notification-architecture-power-automate-separation" rel="noopener noreferrer"&gt;Notification Architecture&lt;/a&gt; - Notifications that cannot break business logic&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/fetchxml-power-automate-odata-filter-alternative" rel="noopener noreferrer"&gt;FetchXML in Power Automate&lt;/a&gt; - When OData $filter is not enough&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/build-dataverse-solution-zip-programmatically" rel="noopener noreferrer"&gt;Building Solution ZIPs&lt;/a&gt; - The undocumented packaging guide&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/ai-power-platform-mistakes" rel="noopener noreferrer"&gt;What AI Gets Wrong&lt;/a&gt; - And why human correction is the point&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/spec-driven-power-automate-14-flows" rel="noopener noreferrer"&gt;Spec-Driven Power Automate&lt;/a&gt; - The full story&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/notification-architecture-power-automate-separation/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Tag-Based Flow Architecture in Power Automate</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Fri, 11 Sep 2026 17:27:04 +0000</pubDate>
      <link>https://dev.to/az365ai/tag-based-flow-architecture-in-power-automate-1jno</link>
      <guid>https://dev.to/az365ai/tag-based-flow-architecture-in-power-automate-1jno</guid>
      <description>&lt;p&gt;Open a production Power Automate flow list. Twenty, maybe thirty flows. Can a new team member tell which ones handle reviews, which handle evaluations, which are notification flows, which fire on signing step changes?&lt;/p&gt;

&lt;p&gt;If the answer takes longer than five seconds, the flows do not have an architecture. They have a list.&lt;/p&gt;

&lt;p&gt;This pattern is what turns a list into a system. Three-letter entity-area tags group flows by the Dataverse table they operate on. Every flow gets a tag prefix, a sequence number, and a type suffix. The result is a small set of tag groups that map cleanly to ADO work items, source control, architecture diagrams, and AI agent batches.&lt;/p&gt;

&lt;p&gt;This builds on the &lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale" rel="noopener noreferrer"&gt;naming conventions&lt;/a&gt; that govern individual flow names. Naming tells you WHAT a flow does. Tags tell you WHERE it belongs in the architecture.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three-letter entity-area tags (REV, EVL, STP, NTF) group Power Automate flows by the Dataverse table they operate on. Every flow gets a tag prefix, a sequence number, and a type suffix. The result is a navigable architecture that maps to ADO work items, source control, diagrams, and AI agent batches.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Ftag-based-flow-architecture-four-tag-map.svg%3Fv%3De376c320" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Ftag-based-flow-architecture-four-tag-map.svg%3Fv%3De376c320" alt="Architecture map showing four tag groups (REV, EVL, STP, NTF) connecting Dataverse tables to ADO, source control, and AI agents" width="928" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Flat Flow Lists
&lt;/h2&gt;

&lt;p&gt;A flat list looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AssignEvaluator-Author&lt;/li&gt;
&lt;li&gt;AssignFirstSigner&lt;/li&gt;
&lt;li&gt;Author Past Due&lt;/li&gt;
&lt;li&gt;Author Reminder&lt;/li&gt;
&lt;li&gt;ChainAdvance&lt;/li&gt;
&lt;li&gt;CreatePersonnelEvaluations&lt;/li&gt;
&lt;li&gt;Cycle Closed&lt;/li&gt;
&lt;li&gt;Cycle Launched&lt;/li&gt;
&lt;li&gt;Evaluation Complete&lt;/li&gt;
&lt;li&gt;Form Assigned&lt;/li&gt;
&lt;li&gt;Ready for Acknowledgment&lt;/li&gt;
&lt;li&gt;Ready for Signature&lt;/li&gt;
&lt;li&gt;Rejection to Author&lt;/li&gt;
&lt;li&gt;ResolveSigner&lt;/li&gt;
&lt;li&gt;Signer Heads-Up&lt;/li&gt;
&lt;li&gt;Signer Past Due&lt;/li&gt;
&lt;li&gt;StepAwaiting&lt;/li&gt;
&lt;li&gt;StepRejected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Names in alphabetical order. No hierarchy. No grouping. There is no way to tell which flows touch the same table, which are notifications versus business logic, or which fire on a schedule versus in real time.&lt;/p&gt;

&lt;p&gt;When a notification requirement lands and a flow count doubles overnight, a flat list collapses fast. In &lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see" rel="noopener noreferrer"&gt;Flow Inventory&lt;/a&gt;, the argument is that discovery without classification is just a list. Tags are the classification layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tag System
&lt;/h2&gt;

&lt;p&gt;Four three-letter tags organize flows by entity area. The illustrative example below uses a performance management application built on three core Dataverse tables, plus a notification layer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Entity Area&lt;/th&gt;
&lt;th&gt;Example Flow Count&lt;/th&gt;
&lt;th&gt;Dataverse Table&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;REV&lt;/td&gt;
&lt;td&gt;Review Cycle&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;app_personnelreviewcycle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EVL&lt;/td&gt;
&lt;td&gt;Evaluation&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;app_personnelevaluation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STP&lt;/td&gt;
&lt;td&gt;Signing Step&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;app_evaluationsigningstep&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF&lt;/td&gt;
&lt;td&gt;Notification&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;Read-only across all tables&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each tag maps to exactly one Dataverse entity area. REV flows only touch &lt;code&gt;app_personnelreviewcycle&lt;/code&gt;. EVL flows only touch &lt;code&gt;app_personnelevaluation&lt;/code&gt;. STP flows only touch &lt;code&gt;app_evaluationsigningstep&lt;/code&gt;. NTF flows query across tables but never write to any of them.&lt;/p&gt;

&lt;p&gt;This is a strict rule, not a guideline. A flow tagged STP only does signing step logic. If a flow needs to touch two entity areas, it calls a child flow. The tag stays clean.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Naming Pattern
&lt;/h3&gt;

&lt;p&gt;Every flow follows this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;App&amp;gt; | [{TAG}{##}] {Description} - {Type}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Northwind | [REV01] CreatePersonnelEvaluations - Business Logic&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Northwind | [EVL03] EvalAccessTeam - Business Logic&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Northwind | [STP01] ChainAdvance - Business Logic&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Northwind | [NTF01] Form Assigned - Daily Digest&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This builds on the foundational naming pattern from &lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale" rel="noopener noreferrer"&gt;Naming Conventions That Scale&lt;/a&gt;. That article covers the base layer: project prefix, descriptive names, consistent formatting. Tags are the next layer up. They add architectural grouping on top of individual flow names.&lt;/p&gt;

&lt;h3&gt;
  
  
  Channel Suffixes for Notifications
&lt;/h3&gt;

&lt;p&gt;The NTF tag accepts a channel suffix to future-proof for multi-channel delivery:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NTF-EMAIL&lt;/code&gt; for email notifications&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NTF-INAPP&lt;/code&gt; for in-app notifications&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NTF-TEAMS&lt;/code&gt; for Microsoft Teams adaptive cards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Designing the naming structure for channels that do not exist yet pays off later. When a Teams integration ships, &lt;code&gt;NTF-TEAMS-01&lt;/code&gt; slots in. No renaming. No restructuring.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Microsoft agrees on prefixes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Microsoft's own &lt;a href="https://learn.microsoft.com/power-automate/guidance/coding-guidelines/use-consistent-naming-conventions" rel="noopener noreferrer"&gt;coding guidelines&lt;/a&gt; recommend categorizing components with prefixes or tags to "help team members quickly identify the role of each component within the flow." Their examples use component-level prefixes like "Trg_" for triggers. Entity-area tags are the next level up. Same principle, applied to entire flows instead of individual actions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How Tags Map to Everything
&lt;/h2&gt;

&lt;p&gt;Tags are not a naming trick. They are an organizational primitive that maps to every tool in the development lifecycle.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Artifact&lt;/th&gt;
&lt;th&gt;How Tags Appear&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Power Automate&lt;/td&gt;
&lt;td&gt;[TAG##] prefix in display name&lt;/td&gt;
&lt;td&gt;Northwind | [EVL01] AssignEvaluator-Author&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure DevOps&lt;/td&gt;
&lt;td&gt;Tag in work item title&lt;/td&gt;
&lt;td&gt;EVL01: Assign evaluator on Draft status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Architecture diagrams&lt;/td&gt;
&lt;td&gt;Labeled boxes per tag group&lt;/td&gt;
&lt;td&gt;REV group, EVL group, STP group, NTF group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source control&lt;/td&gt;
&lt;td&gt;Tag-based file naming&lt;/td&gt;
&lt;td&gt;flows/Northwind-EVL01-AssignEvaluator.json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI agent batches&lt;/td&gt;
&lt;td&gt;Grouped by tag for parallel generation&lt;/td&gt;
&lt;td&gt;Agent 1: NTF01, NTF10, NTF11 (author-facing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Priority tiers&lt;/td&gt;
&lt;td&gt;Tags define deployment phases&lt;/td&gt;
&lt;td&gt;REV/EVL/STP = Phase 1, NTF P1 = Phase 2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When an ADO work item is titled "EVL01: Assign evaluator on Draft status," the exact flow it maps to, the exact table it touches, and the exact solution it lives in are all determined. When a file in source control is named &lt;code&gt;Northwind-EVL01-AssignEvaluator.json&lt;/code&gt;, the same is true. One tag, one concept, across every tool. This only works when flows are &lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm" rel="noopener noreferrer"&gt;solution-aware&lt;/a&gt;. Loose flows cannot be grouped or governed this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample Inventory
&lt;/h2&gt;

&lt;p&gt;Here is a sample inventory using the four-tag taxonomy on a hypothetical performance management application. The point is to show structure, not to prescribe a specific flow set.&lt;/p&gt;

&lt;h3&gt;
  
  
  Business Logic Flows
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Flow Name&lt;/th&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;REV01&lt;/td&gt;
&lt;td&gt;CreatePersonnelEvaluations&lt;/td&gt;
&lt;td&gt;Review status set to Open&lt;/td&gt;
&lt;td&gt;Creates evaluation records from template roles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;REV02&lt;/td&gt;
&lt;td&gt;ReviewAccessTeam&lt;/td&gt;
&lt;td&gt;Review created&lt;/td&gt;
&lt;td&gt;Adds reviewee, supervisor, coach to review access team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EVL01&lt;/td&gt;
&lt;td&gt;AssignEvaluator-Author&lt;/td&gt;
&lt;td&gt;Evaluation status set to Draft&lt;/td&gt;
&lt;td&gt;Resolves evaluator by role, assigns ownership&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EVL02&lt;/td&gt;
&lt;td&gt;AssignFirstSigner&lt;/td&gt;
&lt;td&gt;Evaluation status set to Submitted&lt;/td&gt;
&lt;td&gt;Finds step 1, assigns first signer, sets Signing Off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EVL03&lt;/td&gt;
&lt;td&gt;EvalAccessTeam&lt;/td&gt;
&lt;td&gt;Evaluator field populated&lt;/td&gt;
&lt;td&gt;Adds evaluator to access teams, creates Step 0 (Authoring)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EVL04&lt;/td&gt;
&lt;td&gt;StampSigningConfig&lt;/td&gt;
&lt;td&gt;Evaluation created&lt;/td&gt;
&lt;td&gt;Parses template signing config JSON, creates signing step rows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EVL05&lt;/td&gt;
&lt;td&gt;ResolveSigner&lt;/td&gt;
&lt;td&gt;Signer role changed&lt;/td&gt;
&lt;td&gt;Role-based signer resolution from organizational hierarchy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STP01&lt;/td&gt;
&lt;td&gt;ChainAdvance&lt;/td&gt;
&lt;td&gt;Step status set to SignedOff&lt;/td&gt;
&lt;td&gt;Advances to next signer or sets Fully Signed Off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STP02&lt;/td&gt;
&lt;td&gt;StepAwaiting&lt;/td&gt;
&lt;td&gt;Step status set to Awaiting&lt;/td&gt;
&lt;td&gt;Adds signer to evaluation and review access teams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STP03&lt;/td&gt;
&lt;td&gt;StepRejected&lt;/td&gt;
&lt;td&gt;Step status set to Rejected&lt;/td&gt;
&lt;td&gt;Resets evaluation to Draft, reassigns ownership to author&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Look at the tag column. Without reading anything else, the structure is visible: 2 review flows, 5 evaluation flows, 3 signing step flows. Each group maps to one Dataverse table. Each flow performs exactly one logical operation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Building something similar?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for Power Platform governance patterns and architecture deep dives.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Notification Flows (Scheduled)
&lt;/h3&gt;

&lt;p&gt;A scheduled batch runs daily on weekdays. Each flow handles exactly one notification type.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Table Queried&lt;/th&gt;
&lt;th&gt;Recipient&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NTF01&lt;/td&gt;
&lt;td&gt;Form Assigned&lt;/td&gt;
&lt;td&gt;app_personnelevaluation&lt;/td&gt;
&lt;td&gt;Author&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF02&lt;/td&gt;
&lt;td&gt;Ready for Signature&lt;/td&gt;
&lt;td&gt;app_evaluationsigningstep&lt;/td&gt;
&lt;td&gt;Signer (non-self)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF03&lt;/td&gt;
&lt;td&gt;Ready for Acknowledgment&lt;/td&gt;
&lt;td&gt;app_evaluationsigningstep&lt;/td&gt;
&lt;td&gt;Employee (self-signer)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF04&lt;/td&gt;
&lt;td&gt;Signer Heads-Up&lt;/td&gt;
&lt;td&gt;app_evaluationsigningstep&lt;/td&gt;
&lt;td&gt;Signer (future)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF07&lt;/td&gt;
&lt;td&gt;Evaluation Complete&lt;/td&gt;
&lt;td&gt;app_personnelevaluation&lt;/td&gt;
&lt;td&gt;Author&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF08&lt;/td&gt;
&lt;td&gt;Cycle Launched&lt;/td&gt;
&lt;td&gt;app_personnelreviewcycle&lt;/td&gt;
&lt;td&gt;All participants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF09&lt;/td&gt;
&lt;td&gt;Cycle Closed&lt;/td&gt;
&lt;td&gt;app_personnelreviewcycle&lt;/td&gt;
&lt;td&gt;All participants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF10&lt;/td&gt;
&lt;td&gt;Author Reminder&lt;/td&gt;
&lt;td&gt;app_personnelevaluation&lt;/td&gt;
&lt;td&gt;Author&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF11&lt;/td&gt;
&lt;td&gt;Author Past Due&lt;/td&gt;
&lt;td&gt;app_personnelevaluation&lt;/td&gt;
&lt;td&gt;Author&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF12&lt;/td&gt;
&lt;td&gt;Author Past Due Supervisor Escalation&lt;/td&gt;
&lt;td&gt;app_personnelevaluation&lt;/td&gt;
&lt;td&gt;Author's supervisor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF13&lt;/td&gt;
&lt;td&gt;Signer Past Due&lt;/td&gt;
&lt;td&gt;app_evaluationsigningstep&lt;/td&gt;
&lt;td&gt;Signer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF14&lt;/td&gt;
&lt;td&gt;Signer Past Due Supervisor Escalation&lt;/td&gt;
&lt;td&gt;app_evaluationsigningstep&lt;/td&gt;
&lt;td&gt;Signer's supervisor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice the numbering gap: there is no NTF05 or NTF06 in this table. Those are real-time flows, listed below. The numbers are stable identifiers, not sequential counters. Gaps are fine. Renumbering is not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notification Flows (Real-Time)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;Recipient&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NTF05&lt;/td&gt;
&lt;td&gt;Rejection to Author&lt;/td&gt;
&lt;td&gt;Step status changed to Rejected&lt;/td&gt;
&lt;td&gt;Author&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTF06&lt;/td&gt;
&lt;td&gt;Rejection to Previous Signers&lt;/td&gt;
&lt;td&gt;Step status changed to Rejected&lt;/td&gt;
&lt;td&gt;Previous signers (all with SignedOff status and lower stepOrder)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These two flows fire immediately on rejection events. Everything else is batched into daily digests. That is a deliberate design choice. If a supervisor escalation flow fired in real time, a supervisor with 15 overdue evaluators would receive 15 emails in seconds. A daily digest produces one email per supervisor. Tags make this distinction visible at the inventory level.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Priority tiers matter for deployment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not every notification flow ships at once. P1 flows are must-have for go-live. NTF04 (signer heads-up) is often P2, nice to have, ships after launch. Cycle broadcasts (NTF08, NTF09) are typically P3 and deferrable. Tags let you define these tiers without a separate tracking document.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Tags Enable AI-Assisted Development
&lt;/h2&gt;

&lt;p&gt;Tags are more than an organizational nicety. They are an architectural requirement for AI-assisted development. Because each tag maps to one Dataverse table and one functional area, you can hand an AI agent a scoped batch of flows with only the context it needs. No cross-table confusion, no conflicting patterns, no prompt bloat from unrelated flows.&lt;/p&gt;

&lt;p&gt;A reasonable batching strategy for the notification layer above:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Tag Group&lt;/th&gt;
&lt;th&gt;Flows&lt;/th&gt;
&lt;th&gt;Why This Batch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent 1&lt;/td&gt;
&lt;td&gt;Author-facing&lt;/td&gt;
&lt;td&gt;NTF01, NTF10, NTF11&lt;/td&gt;
&lt;td&gt;Same table, same recipient type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent 2&lt;/td&gt;
&lt;td&gt;Signer-facing&lt;/td&gt;
&lt;td&gt;NTF02, NTF03, NTF04&lt;/td&gt;
&lt;td&gt;Same table, same recipient type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent 3&lt;/td&gt;
&lt;td&gt;Event + completion&lt;/td&gt;
&lt;td&gt;NTF05, NTF06, NTF07&lt;/td&gt;
&lt;td&gt;Event-driven triggers, distinct from scheduled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent 4&lt;/td&gt;
&lt;td&gt;Escalation + broadcast&lt;/td&gt;
&lt;td&gt;NTF08, NTF09, NTF12, NTF13, NTF14&lt;/td&gt;
&lt;td&gt;Supervisor resolution pattern, cycle queries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Flows within a tag group share the same Dataverse table, the same query patterns, and the same recipient resolution logic. The author-facing batch only needs context about &lt;code&gt;app_personnelevaluation&lt;/code&gt; and author-facing email templates. The signer-facing batch only needs context about &lt;code&gt;app_evaluationsigningstep&lt;/code&gt; and signer-facing templates.&lt;/p&gt;

&lt;p&gt;Without tags, a single AI agent would need full context on all notification flows simultaneously. With tags, each agent thread operates on a focused batch. The patterns (variable initialization, FetchXML queries, Apply-to-each loops, SharedMailboxSendEmailV2 actions) are documented in a spec. Tags define the batches. Specs define the patterns. The AI executes.&lt;/p&gt;

&lt;p&gt;This is the value of tags that nobody else is writing about. Naming conventions are not just for humans reading flow lists. They are grouping signals for AI systems building flows in parallel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Tags in a Project
&lt;/h2&gt;

&lt;p&gt;You do not need a complex application to use tags. Here is how to start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Identify entity areas.&lt;/strong&gt; Look at the Dataverse tables. Group flows by the primary table they trigger from or operate on. Each group gets a 3-letter tag. For an Accounts, Contacts, and Opportunities domain, the tags might be ACC, CON, OPP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Number sequentially within each tag.&lt;/strong&gt; ACC01, ACC02, CON01, CON02. Numbers indicate creation order, not priority or importance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Add channel suffixes for multi-channel flows.&lt;/strong&gt; If notification flows could span email, Teams, and in-app, use NTF-EMAIL, NTF-TEAMS, NTF-INAPP. If only email exists today, still use NTF-EMAIL. The convention is ready before the channels exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Use the same tags everywhere.&lt;/strong&gt; ADO work items, architecture diagrams, file names, solution XML. One tag, one concept, across all tools. If EVL01 means "assign evaluator" in Power Automate, it means "assign evaluator" in the ADO backlog, the architecture diagram, and the source control folder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Document the tag dictionary.&lt;/strong&gt; A reference table mapping every tag to its entity area, Dataverse table, and flow count. Keep it in solution documentation. Update it when flows are added. This is the single source of truth.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Start small&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Six flows is enough to benefit from tags. Even at six, tags tell you which entity area each flow belongs to. The system pays for itself the first time someone asks "which flows touch the evaluation table?" and the answer comes in two seconds instead of after opening each flow individually.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Microsoft recommends codifying naming conventions in a style guide so all team members follow the same standards. Your tag dictionary is that style guide. Pin it. Put it in the repo README.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Difference Tags Make
&lt;/h2&gt;

&lt;p&gt;Side by side, before and after:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Without Tags&lt;/th&gt;
&lt;th&gt;With Tags&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AssignEvaluator-Author&lt;/td&gt;
&lt;td&gt;Northwind | [EVL01] AssignEvaluator-Author - Business Logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Form Assigned&lt;/td&gt;
&lt;td&gt;Northwind | [NTF01] Form Assigned - Daily Digest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChainAdvance&lt;/td&gt;
&lt;td&gt;Northwind | [STP01] ChainAdvance - Business Logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Author Past Due Supervisor Escalation&lt;/td&gt;
&lt;td&gt;Northwind | [NTF12] Author Past Due Supervisor Escalation - Daily Digest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ReviewAccessTeam&lt;/td&gt;
&lt;td&gt;Northwind | [REV02] ReviewAccessTeam - Business Logic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The left column is a list. The right column is an architecture. You can sort by tag, filter by type, group by entity area, and batch for AI generation. Same flows. Different level of control.&lt;/p&gt;

&lt;p&gt;Tags are not overhead. They are the cheapest architectural decision on a Power Platform project. Four three-letter codes turn an unrelated set of flows into a system that can be explained in one table.&lt;/p&gt;

&lt;p&gt;To see tags applied as visual documentation, &lt;a href="https://az365.ai/blog/architecture-diagrams-with-draw-io-mcp-and-claude" rel="noopener noreferrer"&gt;Architecture Diagrams with Draw.io MCP&lt;/a&gt; shows how to generate flow inventory diagrams directly from tag-based inventories like this one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Spec-Driven Power Platform Series
&lt;/h2&gt;

&lt;p&gt;This article is part of a series on building Power Automate solutions with specs, governance, and AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/tag-based-flow-architecture-power-automate" rel="noopener noreferrer"&gt;Tag-Based Flow Architecture&lt;/a&gt; - How 3-letter prefixes make a flow set manageable&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/spec-first-power-automate-development" rel="noopener noreferrer"&gt;Spec-First Development&lt;/a&gt; - Why specs should exist before the designer opens&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/notification-architecture-power-automate-separation" rel="noopener noreferrer"&gt;Notification Architecture&lt;/a&gt; - Notifications that cannot break business logic&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/fetchxml-power-automate-odata-filter-alternative" rel="noopener noreferrer"&gt;FetchXML in Power Automate&lt;/a&gt; - When OData $filter is not enough&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/build-dataverse-solution-zip-programmatically" rel="noopener noreferrer"&gt;Building Solution ZIPs&lt;/a&gt; - The undocumented packaging guide&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/ai-power-platform-mistakes" rel="noopener noreferrer"&gt;What AI Gets Wrong&lt;/a&gt; - And why human correction is the point&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/spec-driven-power-automate-14-flows" rel="noopener noreferrer"&gt;Spec-Driven Power Automate&lt;/a&gt; - The full story&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/tag-based-flow-architecture-power-automate/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>governance</category>
    </item>
    <item>
      <title>FetchXML in Power Automate: When OData $filter Is Not Enough</title>
      <dc:creator>Alex Pechenizkiy</dc:creator>
      <pubDate>Thu, 10 Sep 2026 17:25:27 +0000</pubDate>
      <link>https://dev.to/az365ai/fetchxml-in-power-automate-when-odata-filter-is-not-enough-5bn2</link>
      <guid>https://dev.to/az365ai/fetchxml-in-power-automate-when-odata-filter-is-not-enough-5bn2</guid>
      <description>&lt;p&gt;OData &lt;code&gt;$filter&lt;/code&gt; is the default tool for filtering rows in a Power Automate &lt;strong&gt;List rows&lt;/strong&gt; action. For simple single-table queries it is the right tool. For the kind of queries notification and digest flows actually need, it runs out of capability fast.&lt;/p&gt;

&lt;p&gt;Three failure modes show up over and over in production flows: temporal filters with no native operator, joins across more than one related table, and IN-style filters across multiple GUIDs. FetchXML handles all three cleanly. This article walks the patterns and where each one is worth reaching for.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR - Three things OData cannot do cleanly&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Temporal operators&lt;/strong&gt; like &lt;code&gt;last-x-hours&lt;/code&gt; and &lt;code&gt;olderthan-x-days&lt;/code&gt; have no OData equivalent. You must compute cutoff dates manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linked entity joins&lt;/strong&gt; across multiple tables are fragile with &lt;code&gt;$expand&lt;/code&gt; and break beyond one level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IN with multiple GUIDs&lt;/strong&gt; requires verbose &lt;code&gt;or&lt;/code&gt; chains in OData but is clean XML in FetchXML.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Ffetchxml-power-automate-hero.svg%3Fv%3Dbbe25017" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Faz365.ai%2Fimages%2Fblog%2Fdiagrams%2Ffetchxml-power-automate-hero.svg%3Fv%3Dbbe25017" alt="Decision flowchart for choosing between OData filter and FetchXML based on query requirements" width="633" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where $filter Runs Out
&lt;/h2&gt;

&lt;p&gt;OData &lt;code&gt;$filter&lt;/code&gt; works well for simple queries. &lt;code&gt;statuscode eq 1&lt;/code&gt;. &lt;code&gt;name eq 'Contoso'&lt;/code&gt;. &lt;code&gt;revenue gt 1000000&lt;/code&gt;. For single-table, single-condition filtering, it is the right tool.&lt;/p&gt;

&lt;p&gt;It stops being the right tool in four situations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Temporal operators.&lt;/strong&gt; "Find records modified in the last 24 hours." OData has no &lt;code&gt;last-x-hours&lt;/code&gt;. You would need a Compose action to calculate &lt;code&gt;addHours(utcNow(), -24)&lt;/code&gt;, then string-interpolate the result into a &lt;code&gt;$filter&lt;/code&gt; expression. It works, but it is brittle and ugly. FetchXML gives you &lt;code&gt;operator="last-x-hours" value="24"&lt;/code&gt; as a first-class operator, &lt;a href="https://learn.microsoft.com/power-apps/developer/data-platform/fetchxml/reference/operators" rel="noopener noreferrer"&gt;documented in the FetchXML condition operators reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linked entity joins.&lt;/strong&gt; You need an evaluator's name, a form name, and a reviewee's full name that lives two relationships away. OData &lt;code&gt;$expand&lt;/code&gt; can follow one lookup. Nested &lt;code&gt;$expand&lt;/code&gt; syntax across multiple levels is inconsistently supported across Dataverse connector versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-value IN filters.&lt;/strong&gt; "Find records in status A or status B or status C." OData requires &lt;code&gt;(status eq 'guid1' or status eq 'guid2' or status eq 'guid3')&lt;/code&gt;. FetchXML gives you &lt;code&gt;operator="in"&lt;/code&gt; with child &lt;code&gt;&amp;lt;value&amp;gt;&lt;/code&gt; elements. Cleaner, and it scales to any number of values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ordering combined with complex filtering.&lt;/strong&gt; OData supports &lt;code&gt;$orderby&lt;/code&gt;, but when you combine it with multi-condition filters and expansions, the query string becomes unreadable. FetchXML keeps ordering, filtering, and joins in a structured XML hierarchy.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;OData $filter&lt;/th&gt;
&lt;th&gt;FetchXML&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Simple equality&lt;/td&gt;
&lt;td&gt;Compact one-liner&lt;/td&gt;
&lt;td&gt;Works but verbose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Temporal: last N hours&lt;/td&gt;
&lt;td&gt;Manual date math&lt;/td&gt;
&lt;td&gt;last-x-hours operator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Temporal: older than N days&lt;/td&gt;
&lt;td&gt;Manual date math&lt;/td&gt;
&lt;td&gt;olderthan-x-days operator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Temporal: on or before date&lt;/td&gt;
&lt;td&gt;Must compute or hardcode&lt;/td&gt;
&lt;td&gt;on-or-before with dynamic expression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IN with multiple GUIDs&lt;/td&gt;
&lt;td&gt;Verbose or-chains&lt;/td&gt;
&lt;td&gt;operator="in" with child values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-table joins&lt;/td&gt;
&lt;td&gt;$expand, fragile nested&lt;/td&gt;
&lt;td&gt;link-entity, up to 10 levels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ordering + complex filters&lt;/td&gt;
&lt;td&gt;Readable for simple cases&lt;/td&gt;
&lt;td&gt;Structured XML hierarchy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in pagination&lt;/td&gt;
&lt;td&gt;$top / $skip / nextLink&lt;/td&gt;
&lt;td&gt;Manual paging required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Readability for simple queries&lt;/td&gt;
&lt;td&gt;Winner&lt;/td&gt;
&lt;td&gt;XML verbosity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  FetchXML Fundamentals in Power Automate
&lt;/h2&gt;

&lt;p&gt;FetchXML queries go into the &lt;strong&gt;Fetch Xml Query&lt;/strong&gt; field of the &lt;a href="https://learn.microsoft.com/power-automate/dataverse/list-rows#advanced-options" rel="noopener noreferrer"&gt;&lt;strong&gt;List rows&lt;/strong&gt; action&lt;/a&gt; in the Microsoft Dataverse connector, under Advanced Options.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add a List rows action&lt;/strong&gt; Use the Microsoft Dataverse connector, not the legacy Common Data Service connector. Select your target table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expand Advanced Options&lt;/strong&gt; Look for the 'Fetch Xml Query' field. When you populate this, it overrides the Row Filter field entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paste your FetchXML&lt;/strong&gt; The query starts with  and contains an  element matching the table you selected. Include only the  elements you need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle pagination yourself&lt;/strong&gt; The List rows pagination toggle does NOT work with FetchXML. If you expect more than 5,000 rows, you must implement paging using the page and paging-cookie attributes in your FetchXML.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pagination does not work with FetchXML&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The "Pagination" toggle in List rows settings is ignored when you use a Fetch Xml Query. This means your query returns up to the default page size unless you implement paging. If you need more, manage paging manually using the &lt;code&gt;page&lt;/code&gt; and &lt;code&gt;paging-cookie&lt;/code&gt; attributes on the &lt;code&gt;&amp;lt;fetch&amp;gt;&lt;/code&gt; element. For most notification flows the default page is more than enough. For bulk-processing flows, plan for this. See the &lt;a href="https://learn.microsoft.com/power-automate/dataverse/list-rows#advanced-options" rel="noopener noreferrer"&gt;List rows reference&lt;/a&gt; for the relevant note on aggregation and FetchXML behavior.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every FetchXML query in a &lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm/" rel="noopener noreferrer"&gt;solution-aware flow&lt;/a&gt; should use connection references, not hardcoded connections. The List rows action itself references a Dataverse connection reference. The FetchXML inside it can contain dynamic expressions like &lt;code&gt;@{utcNow()}&lt;/code&gt; that Power Automate evaluates at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Temporal Operators: The Killer Feature
&lt;/h2&gt;

&lt;p&gt;This is where FetchXML earns its place. Dataverse exposes a full library of temporal condition operators that OData does not surface.&lt;/p&gt;

&lt;h3&gt;
  
  
  last-x-hours: Daily Digest Lookback
&lt;/h3&gt;

&lt;p&gt;Consider a daily digest scheduled at 8:00 AM that needs all records assigned in the previous 24 hours. The query against an &lt;code&gt;app_personnelevaluation&lt;/code&gt; table looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;fetch&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt; &lt;span class="na"&gt;output-format=&lt;/span&gt;&lt;span class="s"&gt;"xml-platform"&lt;/span&gt; &lt;span class="na"&gt;mapping=&lt;/span&gt;&lt;span class="s"&gt;"logical"&lt;/span&gt; &lt;span class="na"&gt;distinct=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;entity&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluationid"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluationduedate"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluator"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;filter&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"and"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;condition&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluationstatus"&lt;/span&gt;
                 &lt;span class="na"&gt;operator=&lt;/span&gt;&lt;span class="s"&gt;"eq"&lt;/span&gt;
                 &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"00000000-0000-0000-0000-000000000000"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;condition&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluator"&lt;/span&gt; &lt;span class="na"&gt;operator=&lt;/span&gt;&lt;span class="s"&gt;"not-null"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;condition&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"modifiedon"&lt;/span&gt; &lt;span class="na"&gt;operator=&lt;/span&gt;&lt;span class="s"&gt;"last-x-hours"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"24"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;order&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluator"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/entity&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/fetch&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three conditions that would each require a workaround in OData: the status check is fine, but the null guard and the temporal lookback are not. FetchXML handles all three in a single readable block.&lt;/p&gt;

&lt;p&gt;To do this in OData you would need a Compose action with &lt;code&gt;addHours(utcNow(), -24)&lt;/code&gt;, then reference that output inside the &lt;code&gt;$filter&lt;/code&gt; string. It works, but now you have flow logic split across two actions instead of one self-contained query.&lt;/p&gt;

&lt;h3&gt;
  
  
  olderthan-x-days: Past Due Escalation
&lt;/h3&gt;

&lt;p&gt;A supervisor escalation flow needs records that have been past due for more than 7 days. The &lt;code&gt;olderthan-x-days&lt;/code&gt; operator finds records that have been sitting in an overdue state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;fetch&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt; &lt;span class="na"&gt;output-format=&lt;/span&gt;&lt;span class="s"&gt;"xml-platform"&lt;/span&gt; &lt;span class="na"&gt;mapping=&lt;/span&gt;&lt;span class="s"&gt;"logical"&lt;/span&gt; &lt;span class="na"&gt;distinct=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;entity&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluationid"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluationduedate"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluator"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;filter&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"and"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;condition&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluationstatus"&lt;/span&gt;
                 &lt;span class="na"&gt;operator=&lt;/span&gt;&lt;span class="s"&gt;"in"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&lt;/span&gt;00000000-0000-0000-0000-000000000001&lt;span class="nt"&gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&lt;/span&gt;00000000-0000-0000-0000-000000000002&lt;span class="nt"&gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/condition&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;condition&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluationduedate"&lt;/span&gt;
                 &lt;span class="na"&gt;operator=&lt;/span&gt;&lt;span class="s"&gt;"olderthan-x-days"&lt;/span&gt;
                 &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"7"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;condition&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluator"&lt;/span&gt; &lt;span class="na"&gt;operator=&lt;/span&gt;&lt;span class="s"&gt;"not-null"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;order&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluator"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/entity&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/fetch&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GUIDs are illustrative placeholders. Notice the &lt;code&gt;operator="in"&lt;/code&gt; with child &lt;code&gt;&amp;lt;value&amp;gt;&lt;/code&gt; elements. This checks two statuses (past due and overdue) in a single condition. The OData equivalent would be &lt;code&gt;(app_personnelevaluationstatus eq 'guid1' or app_personnelevaluationstatus eq 'guid2')&lt;/code&gt;. Add the &lt;code&gt;olderthan-x-days&lt;/code&gt; equivalent (which does not exist natively) and you are looking at a query string nobody can debug.&lt;/p&gt;

&lt;h3&gt;
  
  
  on-or-before: Past Due Reminders
&lt;/h3&gt;

&lt;p&gt;A signing-step reminder flow finds steps that are past due. The step must be in "Awaiting" status AND the due date must be on or before right now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;fetch&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt; &lt;span class="na"&gt;output-format=&lt;/span&gt;&lt;span class="s"&gt;"xml-platform"&lt;/span&gt; &lt;span class="na"&gt;mapping=&lt;/span&gt;&lt;span class="s"&gt;"logical"&lt;/span&gt; &lt;span class="na"&gt;distinct=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;entity&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluationsigningstep"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluationsigningstepid"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_duedate"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_steporder"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_signer"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluation"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;filter&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"and"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;condition&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_stepstatus"&lt;/span&gt;
                 &lt;span class="na"&gt;operator=&lt;/span&gt;&lt;span class="s"&gt;"eq"&lt;/span&gt;
                 &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"691090001"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;condition&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_duedate"&lt;/span&gt;
                 &lt;span class="na"&gt;operator=&lt;/span&gt;&lt;span class="s"&gt;"on-or-before"&lt;/span&gt;
                 &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"@{utcNow()}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link-entity&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluation"&lt;/span&gt;
                 &lt;span class="na"&gt;from=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluationid"&lt;/span&gt;
                 &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluation"&lt;/span&gt;
                 &lt;span class="na"&gt;link-type=&lt;/span&gt;&lt;span class="s"&gt;"inner"&lt;/span&gt;
                 &lt;span class="na"&gt;alias=&lt;/span&gt;&lt;span class="s"&gt;"eval"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluator"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/link-entity&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;order&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_signer"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/entity&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/fetch&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@{utcNow()}&lt;/code&gt; expression is evaluated by Power Automate before the query runs. The &lt;code&gt;on-or-before&lt;/code&gt; operator captures everything past due, regardless of whether it is one day or one year overdue.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Working with complex Dataverse queries?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for FetchXML patterns and Power Automate deep dives.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Linked Entity Joins: One Query Instead of Five
&lt;/h2&gt;

&lt;p&gt;A daily digest notification often needs more than the primary record. Suppose the email body needs the evaluator's name, the form name, and the reviewee's full name. The reviewee lives on the &lt;code&gt;app_personnel&lt;/code&gt; table, which connects through &lt;code&gt;app_personnelreview&lt;/code&gt;. That is two joins from the evaluation record.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;fetch&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt; &lt;span class="na"&gt;output-format=&lt;/span&gt;&lt;span class="s"&gt;"xml-platform"&lt;/span&gt; &lt;span class="na"&gt;mapping=&lt;/span&gt;&lt;span class="s"&gt;"logical"&lt;/span&gt; &lt;span class="na"&gt;distinct=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;entity&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluationid"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluationduedate"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluator"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link-entity&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelreview"&lt;/span&gt;
                 &lt;span class="na"&gt;from=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelreviewid"&lt;/span&gt;
                 &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"app_review"&lt;/span&gt;
                 &lt;span class="na"&gt;link-type=&lt;/span&gt;&lt;span class="s"&gt;"inner"&lt;/span&gt;
                 &lt;span class="na"&gt;alias=&lt;/span&gt;&lt;span class="s"&gt;"review"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;link-entity&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_personnel"&lt;/span&gt;
                   &lt;span class="na"&gt;from=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelid"&lt;/span&gt;
                   &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"app_personnel"&lt;/span&gt;
                   &lt;span class="na"&gt;link-type=&lt;/span&gt;&lt;span class="s"&gt;"inner"&lt;/span&gt;
                   &lt;span class="na"&gt;alias=&lt;/span&gt;&lt;span class="s"&gt;"reviewee"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;attribute&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"app_fullname"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/link-entity&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/link-entity&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;filter&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"and"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;condition&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_personnelevaluationstatus"&lt;/span&gt;
                 &lt;span class="na"&gt;operator=&lt;/span&gt;&lt;span class="s"&gt;"eq"&lt;/span&gt;
                 &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"00000000-0000-0000-0000-000000000000"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;condition&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"modifiedon"&lt;/span&gt; &lt;span class="na"&gt;operator=&lt;/span&gt;&lt;span class="s"&gt;"last-x-hours"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"24"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;order&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;"app_evaluator"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/entity&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/fetch&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three tables in one query. Results come back flat with aliased columns: &lt;code&gt;review.app_name&lt;/code&gt; for the review cycle name and &lt;code&gt;reviewee.app_fullname&lt;/code&gt; for the person being reviewed. No secondary "Get a row by ID" actions. No nested Apply to each loops.&lt;/p&gt;

&lt;p&gt;Without FetchXML, this flow would need a List rows to get evaluations, then a Get row for each evaluation's review, then another Get row for each review's personnel record. That is 1 + N + N API calls. With FetchXML, it is 1.&lt;/p&gt;

&lt;p&gt;Dataverse &lt;a href="https://learn.microsoft.com/power-apps/developer/data-platform/fetchxml/join-tables" rel="noopener noreferrer"&gt;supports up to 10 levels of link-entity nesting&lt;/a&gt; per query, and additional link-entities can be added at the same level. In practice, three is usually plenty. If you are nesting deeper than that, the data model probably needs attention before the query does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ordering for Recipient Grouping
&lt;/h2&gt;

&lt;p&gt;This pattern is non-obvious and saves a lot of flow run actions.&lt;/p&gt;

&lt;p&gt;Look at the &lt;code&gt;&amp;lt;order attribute="app_evaluator" /&amp;gt;&lt;/code&gt; in every example above. That is not for display. It is the engine of the daily digest pattern.&lt;/p&gt;

&lt;p&gt;The flow needs to send one email per evaluator containing all their assigned records. Without ordering, you would: get all rows, extract unique evaluator GUIDs, then loop through each GUID and filter the rows. That is O(n^2) in Power Automate actions.&lt;/p&gt;

&lt;p&gt;With ordering, results arrive grouped by evaluator GUID. The flow iterates through the list once. When the evaluator GUID changes from the previous row, it knows: finalize the current email body, send it, start building the next one. One pass. O(n) actions.&lt;/p&gt;

&lt;p&gt;The savings are significant for any digest flow that fans out to multiple recipients. The exact action count depends on the recipient count and average rows per recipient, but the pattern reliably collapses nested-loop work into a single pass and reduces action consumption against the &lt;a href="https://learn.microsoft.com/power-platform/admin/api-request-limits-allocations" rel="noopener noreferrer"&gt;Power Platform request limits&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Should You Use FetchXML Instead of OData?
&lt;/h2&gt;

&lt;p&gt;If your Power Automate flow needs temporal operators like &lt;code&gt;last-x-hours&lt;/code&gt;, joins across multiple Dataverse tables, or &lt;code&gt;IN&lt;/code&gt; filters with several GUIDs, use FetchXML. OData &lt;code&gt;$filter&lt;/code&gt; works for simple single-table queries, but production notification and reporting flows almost always hit at least one limitation that only FetchXML can solve.&lt;/p&gt;

&lt;p&gt;A practical decision framework:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use OData &lt;code&gt;$filter&lt;/code&gt; when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The query filters on a single table with simple conditions&lt;/li&gt;
&lt;li&gt;You need built-in pagination (&lt;code&gt;$top&lt;/code&gt; / &lt;code&gt;$skip&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The query fits in one readable line&lt;/li&gt;
&lt;li&gt;You are building a quick prototype and do not need temporal logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use FetchXML when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need temporal operators (&lt;code&gt;last-x-hours&lt;/code&gt;, &lt;code&gt;olderthan-x-days&lt;/code&gt;, &lt;code&gt;on-or-before&lt;/code&gt;, &lt;code&gt;last-week&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;You need joins across two or more related tables&lt;/li&gt;
&lt;li&gt;You need &lt;code&gt;IN&lt;/code&gt; with multiple values, especially GUIDs&lt;/li&gt;
&lt;li&gt;You need ordering combined with complex filtering&lt;/li&gt;
&lt;li&gt;The query will be maintained by a team and structured XML is easier to read than a long filter string&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A reasonable workflow is to prototype with OData and switch to FetchXML the moment you hit a limitation. For notification flows, that moment usually comes on flow number one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Validate before deploying&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FetchXML queries are powerful but easy to get wrong. A mistyped attribute name returns zero rows with no error. Before promoting FetchXML-heavy flows to production, run the query in &lt;a href="https://learn.microsoft.com/power-apps/developer/data-platform/fetchxml/overview#community-tools" rel="noopener noreferrer"&gt;XrmToolBox's FetchXML Builder&lt;/a&gt; to verify the results. For automated validation, see &lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production/" rel="noopener noreferrer"&gt;AI-powered flow review gates&lt;/a&gt; that can catch query issues before they reach production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Performance Tips
&lt;/h2&gt;

&lt;p&gt;A few practical guardrails that show up across most production FetchXML in Power Automate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Select only the attributes you need.&lt;/strong&gt; Avoid &lt;code&gt;all-attributes&lt;/code&gt;. Every extra column is data transferred from Dataverse to Power Automate. In a flow that runs daily across hundreds of records, this adds up. The official guidance is in &lt;a href="https://learn.microsoft.com/power-apps/developer/data-platform/fetchxml/optimize-performance" rel="noopener noreferrer"&gt;FetchXML performance optimizations&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;exists&lt;/code&gt; link-types when you do not need columns from the joined table.&lt;/strong&gt; If you are filtering by a related record's status but do not need any of its fields in the output, &lt;code&gt;link-type="exists"&lt;/code&gt; skips the join in the result set.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Avoid leading wildcards.&lt;/strong&gt; &lt;code&gt;like '%Smith'&lt;/code&gt; forces a table scan. &lt;code&gt;like 'Smith%'&lt;/code&gt; can use an index. This applies in FetchXML the same way it applies in SQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test your row counts.&lt;/strong&gt; List rows with FetchXML caps at the default page size without manual paging. If your notification flow could plausibly match more, either add tighter filters or implement paging with &lt;code&gt;page&lt;/code&gt; and &lt;code&gt;paging-cookie&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Spec-Driven Power Platform Series
&lt;/h2&gt;

&lt;p&gt;This article is part of a series on building Power Automate solutions with specs, governance, and AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/tag-based-flow-architecture-power-automate" rel="noopener noreferrer"&gt;Tag-Based Flow Architecture&lt;/a&gt; - How 3-letter prefixes make a flow inventory manageable&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/spec-first-power-automate-development" rel="noopener noreferrer"&gt;Spec-First Development&lt;/a&gt; - Why specs should exist before the designer opens&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/notification-architecture-power-automate-separation" rel="noopener noreferrer"&gt;Notification Architecture&lt;/a&gt; - Notifications that cannot break business logic&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/fetchxml-power-automate-odata-filter-alternative" rel="noopener noreferrer"&gt;FetchXML in Power Automate&lt;/a&gt; - When OData $filter is not enough&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/build-dataverse-solution-zip-programmatically" rel="noopener noreferrer"&gt;Building Solution ZIPs&lt;/a&gt; - The undocumented packaging guide&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/ai-power-platform-mistakes" rel="noopener noreferrer"&gt;What AI Gets Wrong&lt;/a&gt; - And why human correction is the point&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://az365.ai/blog/spec-driven-power-automate-14-flows" rel="noopener noreferrer"&gt;Spec-Driven Notification Flows&lt;/a&gt; - The full story&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Power Automate Governance - The Enterprise Playbook
&lt;/h2&gt;

&lt;p&gt;This article is part of a 10-part series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-naming-conventions-that-scale" rel="noopener noreferrer"&gt;Naming Conventions That Scale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-environment-strategy-dev-test-prod" rel="noopener noreferrer"&gt;Environment Strategy - Dev Test Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/solution-aware-power-automate-flows-why-loose-flows-kill-alm" rel="noopener noreferrer"&gt;Solution-Aware Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-flow-inventory-you-cant-govern-what-you-cant-see" rel="noopener noreferrer"&gt;Flow Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-pipelines-moving-flows-from-dev-to-prod" rel="noopener noreferrer"&gt;Pipelines - Dev to Prod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/coe-starter-kit-what-it-does-and-what-to-build-on-top" rel="noopener noreferrer"&gt;CoE Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/ai-powered-flow-review-quality-gates-before-production" rel="noopener noreferrer"&gt;AI-Powered Flow Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-versioning-and-source-control-export-tag-track" rel="noopener noreferrer"&gt;Versioning and Source Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-platform-governance-repo-standards-reviews-inventory" rel="noopener noreferrer"&gt;The Governance Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://az365.ai/blog/power-automate-weekly-governance-digest-automated-health-report" rel="noopener noreferrer"&gt;Weekly Governance Digest&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/"&gt;AZ365.ai&lt;/a&gt; - Azure and AI insights for architects building on Microsoft. &lt;a href="https://www.linkedin.com/in/az365ai/" rel="noopener noreferrer"&gt;Follow Alex on LinkedIn&lt;/a&gt; for architecture deep dives.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://az365.ai/blog/fetchxml-power-automate-odata-filter-alternative/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;. I'm Alex Pechenizkiy, an Azure and Power Platform solutions architect writing honest, vendor-neutral analysis of the Microsoft AI stack. More at &lt;a href="https://az365.ai/" rel="noopener noreferrer"&gt;az365.ai&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>powerplatform</category>
      <category>dataverse</category>
      <category>powerautomate</category>
    </item>
  </channel>
</rss>
