M365Con 2027 – free online conference · 11–22 Jan 2027 · 120 sessions→ m365con.net

2026-08-12 · Season 2

Why Power Platform Is Your Real Automation Layer — Not Custom Code

Why Power Platform Is Your Real Automation Layer — Not Custom Code
Why Power Platform Is Your Real Automation Layer — Not Custom Code Every new automation request in Microsoft Dynamics 365 seems to become a development ticket. A new approval path, Teams notification, reminder, document-generation process, or...

Show notes

Why https://www.m365.fm/power-platform-simply-explained/ Is Your Real Automation Layer — Not Custom Code Every new automation request in Microsoft https://www.m365.fm/categories/power-platform-talk/ seems to become a development ticket. A new approval path, Teams notification, reminder, document-generation process, or integration enters a backlog while the business waits for an available developer. In https://www.m365.fm/mirko-peters/ of M365 FM, Mirko Peters challenges that traditional model and explains why Microsoft Power Platform should become the visible automation layer between Dynamics 365, Dataverse, people, decisions, and connected business systems. This is not an argument against custom code. It is a practical framework for understanding where https://www.m365.fm/power-automate-simply-explained/, https://www.m365.fm/power-apps-simply-explained/, Power Fx, Dataverse, solutions, environment variables, security, and governance belong—and where professional development remains the correct architectural choice. ㅤ THE AUTOMATION ASSUMPTION IS BROKEN Many Dynamics environments begin every process request with the same question: where should we write the code? That question narrows the architecture before the team understands what changed in the business, which decision must be made, who needs to respond, which systems need information, and who owns the process after deployment. Power Platform should sit between a Dynamics event and the surrounding business outcome. It can interpret signals, apply visible rules, coordinate human decisions, connect services, and record what happened. Custom code remains valuable, but it should not automatically own every process change. ㅤ THE OLD DYNAMICS CUSTOMIZATION MODEL In the traditional model, every difference between the standard Dynamics application and the business process becomes another customization. A developer creates a Dataverse plug-in, attaches JavaScript to a form, builds a custom workflow activity, adds a scheduled job, or creates another integration service. Each individual feature may work correctly, but the complete process gradually becomes distributed across assemblies, scripts, workflows, APIs, configuration values, and specialist knowledge. The process owner understands the policy but cannot inspect the technical behavior. The developer understands the implementation but may not own the business decision. Support becomes responsible when something fails, even though it may not know which component triggered the outcome. This creates delivery control without creating true process ownership. ㅤ THE HIDDEN COST OF CUSTOM AUTOMATION The initial development cost is visible because it appears in estimates, project budgets, and delivery reports. The long-term operating cost is distributed across support tickets, testing cycles, incident investigation, documentation updates, platform upgrades, and the time required to locate old business rules. A small policy change can become a multi-day development task when a threshold is hidden inside code. Someone must find the relevant implementation, identify the production version, change it, test related behavior, deploy it correctly, and confirm that nothing else relies on the same value. The business may conclude that Dynamics is slow to change. In reality, the automation model is creating the delay. ㅤ WHY DOCUMENTATION AND SUPPORT OFTEN FAIL Documentation usually describes the process as it existed when the solution launched. The business then changes, developers update the implementation, and the original documents slowly become unreliable. Eventually, the code describes the current system behavior while the documentation describes an older version of the business. Neither gives process owners a clear and trustworthy answer. Support teams feel this problem when a record changes unexpectedly or a notification fails. They can see that something happened, but they may not know whether the cause was a plug-in, JavaScript, a classic workflow, Power Automate, or an external integration. The real escalation path becomes finding the person who remembers the automation. When that person leaves, the organization loses more than technical capacity—it loses the map. ㅤ CUSTOM CODE IS NOT THE ENEMY Custom code still belongs in Dynamics and Power Platform architecture. Some requirements must execute inside the Dataverse transaction before a record is accepted. A plug-in may be the correct choice when a rule must prevent invalid data from being saved, perform a controlled calculation, support a performance-sensitive operation, or guarantee consistent server-side behavior regardless of how the data enters Dataverse. Code also remains appropriate for reusable software components, specialist integrations, PCF controls, custom connectors, products, and technical services with their own lifecycle and interface contracts. The important principle is to keep the code boundary narrow. A plug-in should validate one rule, calculate one result, or perform one controlled operation. It should not quietly become responsible for approvals, reminders, documents, escalations, and several external systems. Code earns its place through architectural necessity and engineering discipline—not through habit. ㅤ THE DIFFERENCE BETWEEN VALIDATION AND ORCHESTRATION Some rules define what must be true before a record can be saved. These belong close to the Dataverse transaction. Other rules determine what should happen after the record already meets that standard. These belong in the automation layer. For example, mandatory legal data may need to block a contract from entering an active state. That is transactional validation. Requesting a legal review, notifying an approver, waiting for a response, and updating the contract afterward are orchestration. Separating these responsibilities prevents users from waiting while unnecessary background work executes synchronously. It also prevents invalid data from entering the system while a downstream automation attempts to correct it later. Enforce what must be true now. Orchestrate what needs to happen next. ㅤ POWER PLATFORM AS THE REASONING LAYER An event only tells the system that something changed. It does not automatically explain why work should begin or what should happen next. An opportunity reaches a stage. A case receives a priority. A customer changes owner. The automation layer must determine whether the business conditions are satisfied, which policy applies, who should respond, and which exception route should be used. Power Automate conditions, approvals, switches, Dataverse data, and Power Fx formulas can make this reasoning visible. Process owners do not need to become developers, but they should be able to understand and validate the policy they own. A decision about sales approval may depend on opportunity value, discount, region, account category, payment terms, ownership, or unresolved risk. These conditions should form a clear sequence rather than disappearing into one hidden block of technical logic. ㅤ A SALES APPROVAL WITHOUT A PLUGIN Consider an opportunity that reaches a commercial threshold. The process may need to confirm the current stage, validate required information, determine the applicable approval route, request a decision, record the outcome in Dataverse, notify the seller, and handle delays or rejection. This process crosses data, policy, people, time, and communication channels. It is orchestration rather than transactional validation. Power Automate can begin from the Dataverse record, evaluate the relevant business context, route approval to the correct person, send information through Teams or Outlook, wait for a response, update the opportunity, and preserve a visible execution history. The business can inspect where the process stopped and why. Support can review the run history instead of searching through an assembly. Policy changes can be delivered through a controlled Power Platform lifecycle without turning every adjustment into a new custom-development project. ㅤ SPEED MEANS TIME TO CHANGE Technical teams often define speed as execution time in milliseconds. Business teams experience speed differently. For them, speed includes the time required to understand a request, implement a change, test it, release it, and support it afterward. A custom plug-in may execute faster than a cloud flow while taking weeks longer to modify and deploy. A flow may take several seconds to complete while allowing the organization to change a business rule safely within days. The correct architecture depends on the requirement. Transactional and high-volume operations may need code-level performance. Human approvals and cross-system business processes usually care more about visibility, adaptability, and time to change. ㅤ AUTOMATION NEEDS ORGANIZATIONAL OWNERSHIP A personal flow can become business-critical without anyone deliberately making that decision. The creator changes role, leaves the company, loses a license, or has a connection expire, and an important process suddenly has no reliable owner. Production automation should not depend on a single employee’s personal identity. It needs an ownership model aligned with the business process, data sensitivity, operating team, and support responsibility. Become a supporter of this podcast: https://www.spreaker.com/podcast/m365-fm-microsoft-365-azure-cloud-power-platform-ai--6704921/support.

Apple Podcasts · Spotify · YouTube · Deezer

Host: Mirko Peters

Guests

Related articles

Transcript

Read the full transcript

Every automation request in Dynamics becomes a development request, a new approval path, a reminder, a team's notification, a document created when a deal changes stage, it lands in a backlog. Then someone asks, which developer can pick it up? That model looks normal, it has existed for years. But it starts from the wrong question, not what changed in the process, not who needs to act, not which system needs to know. It starts with, where do we write the code? And that's where the automation decision already narrows too early. More platform should sit between Dynamics and the work around it. It should handle the signals, decisions, people and connected systems that turn a record change into a business outcome. Custom code still has a place, it just shouldn't become the default answer before anyone understands the process. If you work with Dynamics and you're trying to make better automation choices, subscribe to M365FM. Because the problem usually isn't the tool, it's the model behind the tool. The old model, Dynamics as an application to customize. In the old model, Dynamics arrives as a product. The business starts using it, then the gaps appear, sales wants another rule on an opportunity, service wants a different case route, finance wants approval before someone can change a value, operations wants customer data sent somewhere else when a record reaches a certain status. Each request can look small on its own. But teams often treat the application as fixed, every difference in how the business works needs custom work around the edges. So the request goes to a developer, a plug-in gets written, a JavaScript file gets attached to a form, a custom workflow activity appears, an integration service gets built, maybe a developer adds a web hook or a schedule job or another API endpoint that only one person really understands. The work gets delivered, the ticket closes, everyone moves on. That feels like progress. But feature completion is a weak measure. A feature can work perfectly on release day and still create a problem for the next person who needs to change it. Because the completed feature doesn't show the full process, it shows one technical response to one request, at one moment in time. The business rule now sits inside a plug-in assembly, or inside a script library, or inside a workflow that calls a custom activity, or split across all of them. The person asking for the change may know the policy. The developer may know the code, neither person may see the whole automation. That gap matters. A sales leader might say deals above this amount need approval. Simple enough, but the actual process could depend on the account type, the discount level, the country, the owner's business unit, and whether legal terms changed after the first approval. The conversation begins with code, the team may implement the first version of the rule before anyone has mapped who owns the policy, who responds, what happens when nobody responds, or where the decision needs to appear. The code solves the visible request, the process stays partly invisible. And most organizations repeat this pattern because custom development looks controlled. There's a ticket, there's a sprint, there's a release, there's a developer assigned to the work, but control over delivery isn't the same as control over automation. A process has a life after deployment. Policies change, teams reorganize, thresholds move, new regions appear. Everyone asks for a different escalation route because the old one no longer matches how work happens. Now the original feature isn't just a feature, it's part of the operating system of the business, yet ownership often stays with the build team. The sales operations team owns the approval policy, the platform team owns dynamics, a developer owns the code knowledge. Support owns the incident when it fails. No one owns the complete behavior from event to decision to action. That creates a strange setup, the people closest to the process can describe what needs to change. But they can't inspect the automation. The people who can inspect the automation may not know whether the policy still makes sense, so every small change becomes a translation exercise. Business explains the outcome, an analyst turns it into requirements. A developer turns requirements into code, a tester checks what the developer built, then production receives another technical artifact that someone must remember exists. This isn't an argument against developers, it's an argument against using developers as the routing layer for every business process change. Dynamics has always supported deep extension for good reasons. Some rules need to run inside the dataverse event pipeline. Some calculations need precise technical control, some integrations need code because the surrounding system demands it. But when every gap triggers the same response, the platform becomes a collection of custom answers rather than a clear automation system. You end up with plugins for validation, scripts for user behavior, workflow activities for background work, integrations for notifications. Each piece may behave correctly, together they can become difficult to explain, and if you can't explain why a record triggered work who approved it, what system changed and who owns the failure you don't have an automation layer, you have accumulated customization. The next question is what that accumulation produces over time. The cost nobody put into the business case. The build cost is easy to see, a project gets funded, a developer estimates the work, someone approves the budget, then the plugin goes live. That number ends up in a report, the operating cost goes somewhere else, it lands in support tickets. In test cycles, in meetings where people try to work out why an old rule fired. It lands in the time a senior developer spends reading code they didn't write, because a sales manager needs one approval threshold changed before next week. Nobody calls that a custom code project, but it belongs to the same decision. This is where the business case usually breaks, not because the first build cost was wrong, because it treated delivery as the cost. The real cost begins after delivery. Dynamics changes over time, Microsoft updates the platform. Your forms change, your tables change, security rolls change, another integration starts writing to the same record. A process that looked isolated suddenly sits inside a wider chain of automation. Now every platform release, solution deployment or schema update creates a question. Did the custom logic still behave as expected? That doesn't mean every update breaks code. It means responsible teams need to test the possibility. A plugin may rely on a field being present. A script may assume a form behaves a certain way. A custom workflow activity may rely on data arriving in a specific order. The test effort expands because the behavior isn't always visible from the business process. You need to know the technical path. And often that knowledge lives with a person, not with the organization. Consider a simple request. A commercial director wants to change an approval limit from one amount to another. The policy changed, nothing technical changed. But if that limit sits in code, the request turns into development work. Someone needs to locate the rule, confirm which version runs in production. Change it safely, test the result, deploy it through the right path, then confirm that another part of the code doesn't use the same value for a different reason. The request could take days. Just because changing a number takes days, because changing a hidden rule safely takes days. That's developer dependency. And it doesn't only affect developers. The business weights, the support team weights, the process owner either works around the old rule or sends exceptions through email until the change arrives. Then somebody asks why dynamics feels slow to change. Dynamics isn't slow, the automation model is. Documentation should close that gap. In practice, it often doesn't. At go live, teams document the original requirements. They document the solution design. Maybe they document the assemblies, scripts, endpoints and configuration values. Then the business changes. A manager changes the approval route. A new region needs a different exception. A policy gets simplified. The code gets updated. But the process document stays behind. Soon, the documentation explains the version of the business that existed six months ago. The code explains what the system currently does. Neither one gives a process owner a reliable answer. So they ask around, does this rule still apply? Who owns this integration? Why did the record update? Can we turn this off? It's not a technical failure. It's an ownership failure created by an automation that people can't inspect. Support teams feel this first. A user calls because an opportunity changed status unexpectedly. Or a notification never arrived. Or an external system received the wrong value. Support opens the record. They check the audit history. They can see something happened. But they may not see the rule that decided it. They may not know whether a plug-in ran, whether JavaScript changed a field, whether a custom workflow activity triggered an integration, or whether another system wrote directly into data verse. So the ticket moves. First line support sends it to the dynamics team. The dynamics team sends it to the integration team. The integration team asks the developer to inspect logs. Meanwhile, the user still needs an answer. This creates a hidden support model. The official support process might look clear. The actual support process depends on finding the person who remembers the automation. That person becomes a bottleneck. They may be busy. They may have moved to another team. They may have left. And when they leave, the business doesn't lose just a developer. It loses the map. Power Platform doesn't remove the need for design, testing, or support. That would be a false promise. A badly designed flow can create confusion too. But it can place more of the process in a form that process owners, admins, and support teams can inspect. They can see the trigger. They can see the conditions. They can see the approval branch. They can see the action that failed. That changes the operating cost. Not because nobody needs technical skill, because fewer routine changes begin with a search through custom code. So separate two decisions. The first is whether code can solve the requirement. Usually it can. The second is whether code should own that requirement for the next five years. That decision needs a different standard. Custom code isn't the enemy. Custom code still belongs in dynamics. Some decisions must happen before a record saves. A user enters a value. An integration submits an update. A data import changes a status. Before a dataverse accepts that change, a rule may need to inspect the data and stop it. That's a server side boundary. If a record must never exist in an invalid state, the rule can't wait for an asynchronous flow to run later. It needs to run in the dataverse event pipeline. This is where a plugin can be the right choice. Take a rule that checks a regulated identifier across related records before a case can move forward. Or a rule that prevents a contract from entering an active state when mandatory legal data is missing. The record either passes the rule or doesn't save. That decision needs controlled execution. Not a notification after the fact. Not a cleanup process after bad data already entered the system. And some calculations need the same level of control. A calculation may depend on several related records, a defined sequence of operations, and strict handling of failure. It may need to run once against the right data with a clear result before the next part of the transaction continues. You don't build that as a broad flow because flows can build it. You use the right execution model because the business outcome depends on it. Volume changes the decision too. Imagine an integration processing large numbers of records. Each record creates related work. Each update triggers checks. Each check could call other services. A slow design can create pressure across the whole process. The answer isn't always right more code. And high volume performance sensitive operations need deliberate design. A focused seabass plugin can sometimes perform a narrow piece of work more efficiently than a long chain of connector calls and repeated record queries. It gives developers direct control over queries, execution parts, error handling and resource use. That is one proper reason to use code. There's another case. You may be building something that extends beyond one internal dynamics process, a reusable component, a custom connector, a PCF control for a specific user experience, a product capability used across customers. An external service with its own life cycle and technical contract. These are software components. They need software engineering, version control, tests, clear interfaces, people who understand the technical boundary they own. Trying to force those into a cloud flow just to avoid code doesn't create a better architecture. It creates a harder one to operate. So the argument isn't low code everywhere. That becomes its own flawed model. The question is simpler. Does this requirement need to run inside the transaction? Does it need strict performance control? Does it need a technical component that other systems or products consume? If the answer is yes, code may be the correct layer, but keep it narrow. A plug-in should do one defined job. Validate one rule. Calculate one result. Apply one control change. It shouldn't quietly become the place where an entire business process lives. Once a plug-in starts sending messages, waiting for people creating documents, calling several external systems and deciding escalations, it has crossed the boundary. Now it's carrying orchestration work. When orchestration has different needs, it needs visibility, it needs retries, it needs human decisions, it needs a clear record of what happened when another system didn't respond. A focused plug-in also needs proper failure behavior. If validation fails, return an error that tells the user what to fix, not a vague message that sends them to support. If an unexpected technical error occurs, capture enough detail for the team to investigate without exposing internal information to the user. Then test it under realistic load, not just one record in a development environment. Test the record patterns it will see in production. Test concurrent updates. Test failure parts. Test what happens when related data is missing. Code earns its place through discipline, not through habit. And that distinction clears up the architecture. Use code where the dataverse transaction needs code. Use power platform where the process needs to move across people, systems, time and decisions. That's the automation layer dynamics teams need to define next. Reasoning. The rules between event and action. An event tells you something changed, but it doesn't say what happens next. An opportunity reaches a new stage. A case gets a priority. A customer record changes owner. That change needs a reason. The system decides whether work should start now. The record either meets the policy or it doesn't. The process knows who needs to decide. And the exception path is clear. This is the layer between the event and the action. And it has to stay visible. In most dynamics environments, rules grow one request at a time. If the discount exceeds this amount, ask for approval. Unless the customer belongs to this segment, unless the seller has this role, unless legal already approved the latest terms. Each condition makes sense on its own. Together, they become the actual policy. The problem starts when the policy only lives in technical logic. A process owner can explain the intended rule, but they can't check whether the system follows it without asking someone to inspect an assembly script or a hidden configuration chain. That slows down every conversation. The process owner asks, why did this deal root to that person? The answer shouldn't require a code review. A well-built automation shows the decision path, it shows the threshold. The owner checked the approval condition, the exception. Not because every process owner needs to become a maker. Because they need to validate the policy they own. Power automate gives teams a visual place for that reasoning. Conditions branch the process based on record data. A switch can send different cases through different routes. Approvals can pause work until the right person responds. Exception paths can root work to a queue, create a review task, or notify the right team when the normal route no longer applies. That's not just easier to build, it's easier to challenge. And business rules should be challenged. A rule nobody questions for three years often stops matching the business long before someone notices, take commercial approvals. The decision might depend on the opportunity value, but value alone rarely tells the full story. The process may also check the account category, deal stage, region, discount percentage, payment terms, seller ownership, and whether the customer has an unresolved risk issue. Those conditions don't need to become one giant piece of logic. They need a clear sequence. First, confirm the opportunity reach the right stage. Then check whether the record includes the required data. After that determine the policy route based on value, risk, and ownership. If an exception applies, send it to a defined review path. Otherwise let the standard route continue. That sequence gives people a way to understand the decision. It also gives them a way to change it. A policy owner can see that a regional threshold needs updating. They can review the impact with the platform team. The maker can update the rule inside a managed process, test it, and release it through the proper path. The change stays connected to the process, rather than disappearing into a technical request. Now FX extends this model for focused decisions. It gives makers a formula language for logic that needs more than a simple condition. You can calculate a value, check data across related records, set a result based on defined rules, build a clear expression around a business decision, but keep the scope tight. A formula should express a decision. It shouldn't turn into a hidden process engine inside one unreadable expression. If the logic becomes difficult to read, split it. Name the decision, store the outcome. Make the next step clear. The same principle applies whether you use PowerFX, Flow Conditions, Dataverse, Rules, or Code. People need to see what the automation decided and why. Risk often creates the most useful structure for this. A low-risk request can continue without interruption. A medium-risk request may need a manager's review. A high-risk request may require several checks, a documented decision, and a different approval path. That isn't an arbitrary technical design. It's the business policy expressed as automation. Ownership works the same way. A record owner may handle a normal case. A team owner may handle a shared workload, a specific business unit may need authority over certain customers or regions. The automation can use that context to root work without treating every record as identical, context decides the root. Not the screen someone happened to use. There is still a boundary to protect. Some rules enforce data integrity at the point of save. They belong close to the Dataverse transaction. Other rules decide what happens after the record already meets that standard. They belong in the automation layer. Don't mix those jobs. A required legal value may need to block a record from saving. A request for legal review can happen after the record saves. One protects the data. The other coordinates work around the data. Keeping that split clear prevents a common design mistake. Teams try to force every decision into the synchronous path because it feels immediate. Then the user waits while the system performs work that doesn't need to block them, or they push strict validation into downstream automation, then discover bad data can enter the system before anyone reacts. The system needs the right boundary, enforce what must be true now, then orchestrate what needs to happen next. Once the rules produce a decision, the system has worked to do. That reasoning is still underway, and we're not that far along. Example, the sales approval that doesn't need a plug-in. Take a sales approval. An opportunity reaches a commercial threshold. Maybe the total value passes a limit. Maybe the discount becomes too high. Maybe the payment terms change. The seller updates the opportunity. That update is the event. It doesn't need to become a plug-in just because it triggers work. Start with the business condition. The opportunity needs to reach the correct stage. The seller needs to complete the required fields. The account needs a defined category. The commercial values need to match an approval policy. A flow can check all of that. Not after somebody emails a manager. Not after the seller chases an answer through Teams. The process starts from the record context already in Dynamics. First, the flow checks the opportunity stage. A quote still being drafted shouldn't enter a final approval route. Next, it checks the fields the approval needs. Discount percentage contract length payment terms, expected revenue. Any missing information sends the opportunity back to the seller with a clear request. That stops an approver from receiving a vague task with no basis for a decision. Then the flow applies the approval policy. A standard commercial change may root to the sales manager. A larger discount may need commercial leadership. A deal with unusual terms may need finance or legal included. The policy can use the current owner, the account region, the opportunity value, and the agreed threshold. This is not a technical trick. It's the approval model made visible. The approver receives the request where they work. For many Dynamics teams, that means Teams. The request can include the customer name, the opportunity amount, the discount, the terms that trigger review, a link back to the opportunity they can approve or reject without hunting through a list of records. Email can work too. The point isn't the channel. The point is that the request reaches the person responsible with enough context to decide. If the approver rejects it, the flow writes the outcome back to Dynamics. It records the decision. It records the response time. It can store the comment, the opportunity moves to the appropriate status. The seller receives a message with the result. No manual update. No separate spreadsheet tracking approvals. No uncertainty about whether the decision made it back into the system of record. If the approver accepts, the same thing happens. Dynamics receives the outcome. The seller knows the deal can move forward. The record shows what happened. And the approval doesn't disappear into an inbox. That matters when someone asks later why the deal used a certain discount or why it moved forward under different terms. The decision stays connected to the opportunity. Now consider the part most teams forget. No response. A manager gets busy. They travel. They miss the team's notification. The approval sits there. The seller waits. Without automation, somebody starts chasing. First in teams then by email, then through a manager's manager. That work doesn't improve the deal. It only compensates for a process with no follow-up path. A flow can wait for a defined period. If no response arrives, it sends a reminder. If the delay continues, it escalates to another owner, a shared approval group, or a defined backup approver. The route follows a policy. Not whoever the seller happens to know. That change alone removes a lot of informal work from sales operations. The seller doesn't need to remember every escalation wrote. The approver doesn't need to rely on a message getting buried. And the process owner can see where approval is stalled. Maybe the threshold is too low. Maybe one person receives too many requests. Maybe the approval model needs a different route. Those are business decisions. The flow gives the team evidence to make them. A plug-in could trigger part of this process. Code can call services. Code can create records. But that doesn't mean code should own the approval journey. This work crosses time, people, channels, and record updates. It needs a visible route. It needs a clear outcome. It needs a way to handle silence. The event pipeline has a different job. It should protect the record when the record must not save without a rule being met. Speed means time to change. Not only milliseconds. People talk about speed like it only means execution time. They ask how fast the plug-in ran, how many milliseconds it added to the save, how quickly the record updated. Those questions matter, especially when logic runs during a record operation. A slow plug-in holds up the user. It increases load. It creates a poor experience across a busy dynamics environment. So yes, execution speed matters. But that's only one kind of speed. A business process also has a change speed. A sales policy changes on Monday. The team needs the new rule working by Wednesday. A new manager takes responsibility for a region. An approval route needs to change before the next large deal arrives. A compliance team changes the conditions that require review. How long until the automation reflects that change? That's the speed the business feels. And it often has nothing to do with milliseconds. A plug-in executes quickly during every record update. But changing one routing rule requires a development request, backlog review, technical analysis, code changes, testing, release approval, deployment. The business process still moves slowly. The record saves quickly. The organization changes slowly. Those are different measurements. This is where visual automation changes the conversation. A flow gives people a readable representation of the process. The trigger appears at the top. The check sit below it. The decision branches show the routes. The approval step shows who receives the request. The follow-up action shows what happens after the decision. A process owner doesn't need to read CEG to understand the broad behavior. They can look at the flow with the platform team and ask useful questions. Why does this route apply here? Who owns that approval group? What happens if nobody responds? Should this threshold still exist? Those questions become part of the review. What are separate requirements exercised after the technical design already happened? That shortens the distance between policy and automation. It also changes handover. With custom code, handover depends on documents being current and developers explaining the intent behind classes, methods, configuration and deployment choices. That work has a place, but it becomes fragile when the automation contains ordinary business rules that could have remained visible. A visual flow doesn't remove the need for documentation. It gives documentation somewhere to point. The process owner can see the route. Support can see the failed action. A new maker can see the connection between the trigger and the outcome. The automation becomes easier to review without first reconstructing it. That reduces the time spent translating. And translation slows teams down more than most people admit. A policy owner describes the change. An analyst interprets it. A developer converts it into a technical change. Then the policy owner waits to see whether the result matches what they meant. With a readable automation layer, more of that discussion can happen around the actual process design. The policy owner still shouldn't edit production on a Friday afternoon. He needs that kind of freedom, but they can validate the route before it reaches production. They can see whether the logic matches the policy. They can catch the wrong approver, the missing exception or the outdated threshold, while the change still costs little to fix. That is business speed. It means the organization can correct automation while the context still exists. A routing change doesn't need to become a technical investigation. A threshold change doesn't need to become a code search. A process correction doesn't need to wait until the person who originally built it becomes available. This doesn't mean every visual flow is automatically easy to understand. A badly built flow hides logic behind vague action names, nested conditions, unexplained variables. It becomes just as hard to operate as code. The tool doesn't create clarity. The design does. So build flows for reading, not only for running. Name the trigger clearly. Name the decisions clearly. Use conditions that describe the rule. Keep related steps together. Make exception parts obvious. When somebody opens the automation six months later, they should understand the process before they understand the mechanics. It's standard changes what fast means. Fast is not only a record saving sooner. Fast is a policy owner seeing the rule. Fast is a reviewer understanding the root. Fast is a team fixing the process before manual work becomes normal again. But none of this holds if the automation belongs to nobody. A visible flow with no accountable owner still becomes slow the moment something changes. Ownership, personal flows, create personal automation. A flow can look shared. It can support a whole sales team. It can update hundreds of records. It can send approval requests across regions, but it may still belong to one employee. That's a problem hiding in plain sight. Many flows begin with good intent. Someone sees repetitive work. They build a flow under their own account. It runs correctly. The team benefits. Nobody asks who owns it because the maker still works there. Then the flow becomes part of daily operations. A scheduled flow sends a report every Monday. An automated flow reacts when a dynamics record changes. An approval flow roots commercial decisions. The work becomes normal, but the identity behind it remains personal. A scheduled and automated flows that identity can affect how the flow runs. The flow runs under its assigned owner's plan. Its access, connections and licensing arrangement depend on that setup. So the process hasn't really become organizational automation. It's still attached to an individual employee. That employee may change roles. They may lose access to a system. Their account may be disabled during an exit process. Nobody intends to break the automation, but the automation can break anyway. The business sees the effect later. The report stops arriving. A reminder doesn't send. Approval stop moving. A database update no longer triggers the work people expected. Then support starts investigating. Not because the process changed, because its owner left the company. This is often automation and it creates a strange kind of operational risk. The automation exists, the business relies on it. But nobody has clear authority to maintain it. Nobody can safely change its connection. Nobody knows whether it should still run. Sometimes the flow keeps working for a while. That can be worse. The team assumes everything is fine. Meanwhile, the owner no longer has an active role in the process and the flow still uses access that nobody has reviewed. The ownership isn't a name on an asset. It is an operating responsibility. Someone needs to own the business outcome. Someone needs to own the technical operation. For smaller processes, those may be the same person. For production automation, they often shouldn't be. A process owner answers questions like, does this approval route still match the policy? Who should receive the escalation? What happens when the process fails? A platform owner answers different questions. Which identity runs the automation? Which connections does it use? Who can maintain it? How does the flow move through test and production? Sharing a flow doesn't solve this by itself. You can share a flow with colleagues. You can give them permission to view it. You can give them permission to edit it. That helps with collaboration. But it doesn't automatically change the primary owner. The original identity can still remain at the center of the automation. Teams often discover that after the person is already left. They thought access meant ownership. It doesn't. Access lets someone participate. Ownership defines who carries the operational responsibility. So don't build business-critical automation under a personal identity and hope sharing will turn it into a team asset. Use an identity that matches the process. For unattended automation, that often means a service account with a defined purpose. Not a generic account whose password sits in an old document. Not a shared personal login. A real account with named operational owners, the right licensing, reviewed permissions, and a life cycle that survives staff changes. Its name should explain its role. Its access should be limited to what the flow needs. Its ownership should be documented. When someone reviews the automation, they should know who approves changes to that account, who checks its connections, and who acts when the flow fails. Application users also fit some application to application patterns. The point stays the same. The identity should represent the process boundary. Not the person who happened to build the first version. This is a small design choice at the start. Later, it becomes the difference between a managed process and a hidden dependency. Once automation has clear ownership, the next step becomes possible. You can package the process properly. You can move it between environments. You can separate the automation from the person who first created it. It starts when flows enter solutions. Environment variables keep environments different without rebuilds. A solution can move between environments, but the environment should not be identical. Your test environment uses a test mailbox. Your production environment uses a shared operations mailbox. One flow post to a team's channel for sales operations. Another environment points to a test channel where nobody mistakes a test approval for a real one. The flow design stays the same, the values change. That's what environment variables are for. They hold configuration outside the flow steps. A URL dot a mailbox address, a SharePoint site ID, a Q name, an approval threshold, a system endpoint without them. Make us type these values directly into the flow. The flow sends mail to a fixed address. It links to a fixed site. It calls a fixed URL. It uses a threshold buried inside a condition. Then the flow needs to move from development to test or from test to production. Now somebody must open the flow and replace each value by hand. That creates two problems. First, the package stops being portable. The process design includes details that only apply in one environment. Second, every deployment becomes an editing exercise. Someone can miss an address. Someone can leave a test URL in production. Someone can change the wrong threshold during a late release. Then the process behaves correctly. But in the wrong place, that kind of failure is frustrating because the logic may look fine. The flow triggered. The approval root worked. The record updated. But the notification went to the test mailbox. Or production wrote to the wrong sharepoint site. Or the flow sent data to an endpoint that no longer belongs to the active process. The issue didn't come from the automation logic. It came from configuration mixed into the logic. Environment variables separate those concerns. The flow defines what needs to happen. The environment variable defines where it happens. Who receives it? Or which value controls the root? Take an opportunity approval process. The logic says deals above a certain limit need commercial review. That rule belongs in the process. But the amount differs between test and production. In test, the team uses a low threshold to create approval scenarios quickly in production. The real policy uses the live threshold, the same flow supports both. No redesign, no copied version, no maker opening each condition and hoping nothing else changes. During deployment, the target environment receives the right value. The package stays consistent. The behavior changes only where the environment needs it to change. That gives test a real purpose. Testing should not mean building a near copy of production and manually adapting every flow it should mean validating the same automation package with controlled configuration. The test mailbox receives the message. The test side stores the document. The test queue receives the task. The test endpoint receives the request. Then, when the same package reaches production, the live values take over. The flow itself doesn't need a new shape. It needs the right configuration. This also works when the business changes without changing the whole process. A shared mailbox changes. A queue moves to another team. A site gets replaced. A threshold changes under an approved policy update. If the value sits in an environment variable, the team can manage that configuration through the proper route instead of editing the flow structure. That keeps process changes and configuration changes separate. They may need different reviews. Changing an approval path may need process owner sign off and testing. Changing a mailbox address may need confirmation from the service owner. Both changes matter. But they aren't the same kind of change. So give configuration a clear owner. A mailbox should have an owner. A queue should have an owner. An external URL should have an owner. A threshold should have a named policy owner. Too many teams treat configuration as nobody's job because it seems small. Then an old mailbox remains in use. A retired endpoint stays in a variable. A queue name points to a team that no longer handles the work. The automation keeps doing exactly what it was configured to do. Which is the problem. Configuration needs review dates. It needs named accountability. It needs a simple place where people can see what each value controls. Otherwise, you move hidden dependencies out of code and place them in unmanaged settings. That isn't progress. The goal isn't just to make deployment easier. It's to make the automation honest about what changes by environment and who controls those changes. Once flows, connections and configuration can travel as one managed unit. The next question is how you deploy that unit without turning production into a workshop. Managed solutions create a boundary around production. Production needs a boundary. Not because people can't be trusted. Because urgent changes feel reasonable at the time. A flow fails. A manager needs a root changed. A mailbox stops working. Someone opens production and fixes it. The process starts working again. Now production differs from the source solution. And the next deployment doesn't know that. A managed solution protects against that pattern when you import a managed solution into production. The package components cannot be directly edited in the normal way. The flow. App. Table changes. Connection references and other components arrive as a release. They remain tied to that release. That creates a clear rule if something needs to change. Change it where the solution is authored. Test it. Then deploy a new version without that boundary. And it becomes its own branch of the system. Not an official branch. A hidden one. Someone changes a flow in production to solve an urgent issue. Another person updates the source solution in development. Then the next managed deployment arrives. Now the team has two versions of the same process. One version exists in the source. Another exists in production. Neither one fully describes the live behavior. This is where unmanaged layers create confusion. A managed solution can exist in production. Then somebody adds a direct change on top of it. That change becomes an unmanaged layer. It may override the behavior shipped in the managed package. The process still works. Until another release arrives. Then the team needs to work out which part came from the package. Which part came from the production edit? And whether the new release will replace. Preserve. Or conflict with that change. Nobody wants to investigate solution layers during an incident. Yet that's where week release habits lead. The fix may have taken five minutes. The recovery later can take days because the team now has to reconstruct intent. Was the production edit temporary? Did anyone document it? Did the same change reach development? Did it reach test? Does the current source still represent the process the business relies on? A production patch can feel like speed. Often it only moves the work forward. The correct response is to fix the source solution. If a flow route needs changing, update the unmanaged solution in development. If a configuration value needs correction. Update it through the defined process. If a defect exists, reproduce it in the right environment. Apply the fix, test the outcome, and release it. That takes more discipline than opening the live flow. But it means the source continues to describe the product. And production continues to run a tested version of that product. This is where version numbers stop being administrative detail. A version identifies what the environment received. When a release enters production, the team should know what changed. Which process rule changed? Which defect was fixed? Which flow version now handles the work? When an issue appears? The team can ask a useful question. Did the start after version 2.4? That is a better starting point than searching through a live environment for changes nobody recorded. The version also creates a rollback conversation. Not every release needs a full reversal, but teams need to know what they can restore, what dependencies exist. And which tested version came before the current one? That knowledge comes from release discipline. Not from hoping the last export file still exists somewhere. Operational pressure exposes every week point. A senior leader wants an immediate change. A customer waits. An approval route fails at the wrong moment. The temptation is always the same. Just fix it in production. Sometimes an emergency response is unavoidable. But if emergency edits become normal. And no longer emergencies, they are the operating model. And that model creates drift, unclear ownership. And deployments nobody trusts. A mature team can still respond quickly. It has a defined emergency path. It records the change. It brings the fix back into the source solution. It tests and deploys the corrected version, so production does not stay different. That's the discipline. Not slowness. Not bureaucracy. A managed solution doesn't stop the business from changing. It stops untrag change from becoming permanent system behavior. And this is the shift people often miss. Governance isn't a queue that blocks automation. It defines the choices that let automation change without breaking production. Governance is the operating model, not the approval queue. Governance gets treated like a gate. A maker has an idea. They submit a request. It reviews it. The request waits. Then people decide governance slows everything down. But that is not governance. That is an approval queue pretending to be a strategy. Here's what governance actually does. It defines where different kinds of automation belong. It defines who can build, who can access data, who owns the process, and how a working idea becomes something the organization can rely on. The starting point is the environment. An environment is a container. It holds the apps, flows, connections, tables, and dataverse resources used for a purpose. And that purpose might be personal productivity. It might be a department process. It might be a production capability used across the company. Those are not the same thing. So they should not all follow the same rules. A personal automation can help one person save time. Maybe it sorts messages. Maybe it creates a reminder. Maybe it moves information between tools that person already uses. That work needs a safe place to exist. It should not need a full production release process. But it also should not quietly become the process that runs a department. Team automation sits in the middle. More people rely on it. It may use shared data. It may connect to a shared mailbox or a team's channel. It needs clearer ownership, defined access, and a path to support. Production automation has a different standard again. It affects customers, revenue, compliance, or core operations. It needs named owners. It needs control deployment. It needs monitoring. It needs an identity and access model that survives staff changes. A clear path for each type of work helps people choose correctly at the start. Instead of asking, can I build this? They ask, what kind of automation is this becoming? That one question prevents a lot of confusion later. Roads make the boundary real. Environment rolls control who can administer or build in an environment. Resource permissions control who can use edit or share a specific app or flow. Dataverse security rolls control, what data people can read, create, update, or delete. These are separate layers. And teams get into trouble when they treat them as one thing. Giving someone access to build a flow does not mean they should access every customer record. Giving someone a dataverse role does not mean they should edit production automation. Giving a user permission to run an app does not mean they should administer its environment. Each permission answers a different question. Who can build? Who can operate? Who can access the data? When those answers stay distinct, automation remains inside the business boundaries already defined in dynamics and dataverse. The power platform admin has a central role here, not as the person who builds every flow, not as the person who approves every small improvement. The admin creates the conditions for safe work. Environment strategy, access rules, support routes, visibility across the platform, a center of excellence can extend that role. It can help makers learn the right patterns. It can identify automation without owners. It can see which connectors are in use. It can find inactive or failing assets before users report a problem. It can guide teams toward the correct environment and delivery path. That is not central control for its own sake. It is shared operational awareness. Without it, every department solves the same problems alone. Who owns this flow? Which environment should we use? How do we deploy it? What happens if the maker leaves? Where do we report a failure? A good operating model answers those questions before they become incidents. And it also avoids forcing every request into IT. I should not become the bottleneck for a sales manager changing a rooting rule or a team improving a low-risk internal process. But the business should not be left alone with production data, shared identities, and unrestricted connectors either. The model gives people room to build within known boundaries. Personal makers get a safe place to experiment. Teams get support for shared automation. Production processes get the discipline their risk requires. That is how you scale automation without creating a second layer of unmanaged work. And once those parts are clear, the next decision is not who can use a connector. It is what data that connector is allowed to move. DLP policies define which data can travel together. A connector is not just a technical option. It is a route for data. And every route needs a decision. Every customer data leave data versed through this connector. Can it move into teams? Can it go to SharePoint? Can it reach a third-party service? The answer should not depend on what a maker happens to select in a flow. That is what data loss prevention policies control. DLP policies group connectors by the type of data they can handle together. One group can contain business data connectors. Another can contain connectors that should not handle business data. A third group blocks connectors entirely. The names are simple. Business? It's a non-business? Blocked. But the decision underneath is specific. If data versed holds customer records, account information, case data or commercial details, an organization may allow that data to work with approved Microsoft 365 services. Maybe outlook, maybe teams, maybe SharePoint. Those connectors can sit in the business data group. A connector placed in the non-business group cannot join that same flow with the business group. The policy stops the combination, not after the data already moved. Before the automation gets built, that is a different model from reviewing every flow by hand. The policy defines the allowed routes once, then make us work within those routes. If a connector is blocked, it cannot be used in power apps or power automate resources covered by that policy. That doesn't mean the connector is bad. It means the organization has decided it does not belong in that environment or with that class of data. A social media connector may make sense for a marketing experiment. It may not belong in an automation that begins with dynamics customer records. A file storage connector may be acceptable for low-risk productivity work. It may not be an approved destination for regulated case information. Here's the real question. Not can power automate connect to it? But should this data travel there? That shift matters. Connector combinations are data risk decisions. A flow can look harmless when each action appears separately. Read an account from dataverse, create a file, post a message, send an HTTP request. But together, those actions define a data route. Where did the data start? Which service received it? Who can access it there? What other systems can that service connect to? DLP policies force the organization to think about that route before a make-up press is safe. The environment should have different levels of freedom. A personal development environment may permit a limited set of low-risk connectors for learning and testing. A team environment may allow approved collaboration services. A production environment containing dynamics data may allow only the connectors needed for a defined business process. That is not inconsistent governance. It is governance based on process sensitivity. A flow that sends an internal reminder doesn't carry the same risk as a flow that moves customer, finance, or case data across systems. Creating both the same either creates unnecessary friction or leaves too much open. External sharing needs the same deliberate decision. A flow can create a connection that crosses tenant boundaries when a user has valid access in another tenant unless the organization restricts that path. That creates a possible route for business data to leave the tenant through an approved looking connection. Some organizations need external collaboration. Suppliers, partners, and acquired businesses may all require data movement. The answer is not always to block every external route. It is to define approved routes. Which external tenants can connect? In which direction? For which environments? For which business processes? A production flow? That sends information to an external partner? Should use an agreed route with ownership and review? It should not depend on a maker signing into another tenant with a personal connection. Security works best when it enters the design at the start. Not when someone discovers a connector after the process already depends on it. The automation layer can move work quickly. That is its purpose. DLP makes sure it does not move business data without a defined boundary, but DLP only governs the route between services. It does not decide who can read or change the dynamics records underneath. Dataverse security keeps automation inside business boundaries. DLP tells data where it can go. Dataverse security tells you who can work with that data before it ever moves. Power Platform does not let users access records they don't already have permission to see. That's the line that matters. A flow connects to dynamics. A user opens an app. A maker builds automation. None of that should become a shortcut around the security underneath. The record still has rules, who can read it, who can update it, who can assign it, who can delete it. Those permissions come from Dataverse security roles. A sales user may read and update their own opportunities. A sales manager sees records across a team. A finance user can access commercial fields that sellers cannot touch. The automation has to respect those boundaries. Otherwise, you get a process that looks controlled on the surface, but actually moves data or updates records with more authority than the business intended. Field-level security adds another layer. Not everyone who sees a record should see every value on it. A customer record might contain sensitive financial information. A case could include restricted notes. A contract may have terms limited to a specific group. Field-level security controls, who reads, creates, or updates those fields that matters for automation too. If a flow uses restricted data, the identity running that flow needs the right permission. No more than that. A broad automation account with system administrator access might feel convenient during a build. But it's also an easy way to hide excessive access inside a process. Nobody reviews. Give the automation only what it needs. If it only reads opportunities and writes approval outcomes, grant that scope. If it needs to create tasks, grant task permissions, if it never deletes records do not grant delete rights just because the account might need them one day. Least privilege is not paperwork. It limits the damage when a connection gets misused, a flow behaves unexpectedly, or an account gets compromised. Auditing gives teams a way to inspect what happened. A record changed. A field changed. And owner changed. The audit trail answers who perform the action and when. For regulated processes, that record may be part of the control itself. For ordinary support work, it separates assumptions from evidence. A customer's start is changed after an approval. Was that a user action? Was it an automation account? Was it an integration? The record history helps the team trace the path. Security also depends on how records are owned. Some tables hold organization-owned records. Those records belong to the organization rather than a specific user or team. They suit shared reference data where personal ownership does not define access. Other tables use user or team ownership. That model matters because ownership shapes who sees a record and who can act on it. An opportunity may belong to a seller. A case may belong to a service team. A shared queue process moves work between owners as responsibility changes. The automation should understand that model before it changes anything. Assigning a record is not just an update. It can change who accesses the record next. It can change who receives follow-up work. Defects reporting, workload views and escalation routes. Business units add another boundary. They structure access around parts of the organization. A company might separate sales regions, legal entities, departments or operational groups through business units and teams. That structure shapes the records people can access through their roles. So an automation that routes work across teams or reassigns records needs to follow the actual security design. It cannot assume every user should see every record just because the flow can find it. Contacts decides the route. But security decides whether that route is allowed. This is where poor automation design often creates silent problems. A flow runs under a powerful identity. It updates records across teams. It bypasses the limits that users experience every day. The process works. But it creates results nobody can explain. A seller sees a record move away from them. A manager receives data from another business unit. A restricted field appears in a notification. The automation did exactly what it's account allowed. The account simply had too much authority. Designed the automation identity around the process. A name-to-count for unattended work where that fits the operating model. Give it a defined security role. Review its permissions. Review where it sits in the business unit and team structure. Then test the automation using the permissions it will actually have in production. Do not build with administrator access and assume normal access will behave the same way later. Security changes who can own automation safely. A personal maker identity may be suitable for low-risk work. A production flow handling shared records, sensitive data or unattended updates needs an owner model that matches the process, the data and the responsibility. Build fewer flows with clearer process boundaries. One business outcome, one primary flow. That should be your default. Not one flow for every small click. Not one flow for every field update. Not a collection of tiny automations that nobody can connect into one process. Take an opportunity approval. The outcome is clear. A deal reaches a point where someone must approve, reject or request changes. That process may check data. It may root approval. It may send reminders. It may update the record. It may notify the seller. Those steps belong together because they produce one business outcome. Splitting them into separate flows can look tidy at first. One flow checks the amount. Another sends the approval. Another writes the outcome. Another sends the reminder. Soon, no one knows which flow owns the process. A failure in one flow leaves the record halfway through the journey. Support has to trace several run histories just to answer a simple question. Did the approval start? Did it finish? Why didn't the seller receive the result? The process boundary disappeared. That doesn't mean every action belongs in one enormous flow. A flow that handles several unrelated outcomes becomes difficult to test and harder to change. The boundary should follow the business result. A customer onboarding flow should own the onboarding outcome. A case escalation flow should own the escalation outcome. A sales approval flow should own the approval outcome. Give each flow a name that says exactly that. Not flow 7, not CRM automation final, not new version. Use names people can search for when the business asks the question. Sales opportunity commercial approval. Customer case, SLA escalation. Contract renewal follow up. The name should tell support what the flow does before they open it. Descriptions matter too. A description can state the trigger, the business owner, the operational owner, the systems involved and the condition that starts the process. It can explain what the flow changes. It can point to the process documentation or support route. That is not busy work. Six months later, it is the difference between an understandable asset and an unexplained dependency. Trigger scope needs the same discipline. A dataverse flow should not react to every update on a table when it only cares about one business change. If an approval begins when an opportunity reaches a certain stage, configure the flow around that condition. Do not wake it up when someone corrects a phone number, add the note or changes in unrelated field. Broad triggers create noise, they create unnecessary runs, they create hidden cost. They also make failures harder to read because the run history fills with work the process never needed to do. Define the entry condition clearly, what changed, which table matters, which columns matter, which status or stage starts the process. Who owns the flow once it runs? These questions create a boundary before the flow even begins. Reusable child flows can help, but only when shared behavior truly exists. A common pattern might create a standard notification, log a process outcome or build a consistent approval summary. If several business processes need that exact behavior, a child flow can keep it in one place. But reuse should not become an obsession, two flows that both send email do not automatically need the same child flow. Their messages may have different owners, different data rules, different failure parts, and different reasons for existing. Fourcing them together creates a shared component nobody can change safely. Reuse works when the responsibility is genuinely shared. The function has one purpose, its inputs are clear, its output is clear, and the team is using it agree on how it should behave, otherwise keep the logic close to the process that owns it. Design the exception route before the happy path feels complete. Most automations look fine when every record contains the right data, every connector response, and every approver replies on time. Production rarely stays that polite, what happens when the record is incomplete, what happens when the approval group has no active members, what happens when the external system rejects the request, what happens when the same record changes again while work is already in progress. Those are not edge cases after launch, they are part of the process, give them a route, notify the right owner. Create a review task, set a status that tells the business what stopped, do not leave a record in silence because the flow expected a perfect path. Circular updates need special attention, a flow triggers on a dataverse update, then it updates the same record, that update can trigger the flow again. Now the process may loop, create duplicate actions, or consume runs without producing useful work, use trigger conditions, update only the fields that need changing. Separate automation state from general record updates where appropriate. People look for competing automations, one flow updates a status, another flow reacts to that status, a plug-in changes the same field, a business rule changes it again, each component may look reasonable alone, together they create unpredictable behavior, map the automation touching a process before adding another one. The question is not can this flow do it? The question is which automation already owns this outcome? When the answer stays clear, the process stays easier to change, but clear design only helps if people can see how the automation behaves after it starts. Everyone starts with an inventory, not a rewrite. Don't start by rewriting plug-ins, start by finding out what exists, most dynamics environments carry years of automation. Some of it still runs every day, some of it only fires when a rare case appears, and some of it stopped mattering years ago. But it still sits there, a migration plan fails when it treats all custom work as one problem, it isn't one problem, you need an inventory first, list every plug-in, every JavaScript library, every classic workflow, every custom workflow activity, every integration, every scheduled job, every flow already touching the same records. Then add one detail people often miss, who owns it, not who built it, who owns the business rule today. A developer may have written a plug-in five years ago that doesn't tell you whether sales, finance, service or legal still wants the outcome. The code describes behavior, it doesn't prove the behavior still belongs in the process. For each item, capture the table it touches, capture the trigger, capture the fields it reads, capture the fields it changes, capture every external system it calls. Then ask a simpler question, what job does this automation actually perform? Some items react to an event, an opportunity changes stage, a case reaches a deadline, a record enters a new status, others apply reasoning, they decide whether a policy applies, they calculate a route, they check whether a condition allows work to continue. Then there is orchestration, the automation sends a notification, it creates a task, it requests approval, it updates another system, it waits, escalates and closes the loop. Lap each asset to those three jobs, event, reasoning, orchestration, one plug-in may contain all three, that is common, a record changes, the plug-in checks several rules, then calls another system and creates follow-up work. That doesn't mean the plug-in was poorly built, it means several responsibilities accumulated in one place, the inventory makes that visible. Once you see the responsibilities, you can discuss the right future boundary. Without that view, teams often replace code line by line, they recreate every old step in a flow, they preserve every old condition, they carry forward every exception, and they rebuild the same complexity using different tools, that isn't modernization, it is relocation. You also need to find dependencies that aren't obvious from the automation name, a plug-in may depend on a field that no one uses on the form. A script may call a web resource used by only one app, a classic workflow may start another workflow, an integration may expect a value to appear in a specific field before it processes the record, a flow may already react to the same status change, these dependencies define the risk, they tell you what could break when you move one piece. And mode matters too. Does the automation run before a record saves? Does it run after the record changes? Does it run in the background? Does it run on a schedule? Does it wait for a person? A name like Opportunity Validation tells you almost nothing about that boundary. The execution mode tells you whether the process affects data integrity, user experience, or downstream work, documented clearly, also document the business owner, not a vague department label, a real person or role responsible for deciding whether the rule remains valid. That conversation can expose surprising things. The team may discover that a complex approval route supports a policy that no longer exists. A script may enforce a field requirement that the business removed from its process years ago. An integration may keep sending data to a system nobody uses, all customizations often remain because nobody wants to touch them. The inventory gives you a safer way to ask whether they should remain. Separate active business rules from abandoned behavior. A rule is active when someone can explain its purpose, confirm its owner, and describe the outcome it still protects. A customization without that evidence is not automatically safe to remove, but it should not receive the same investment as a live process. Market for investigation. Look at whether it still runs. Check whether records still depend on it. Confirm whether another automation already replaced it. Then decide with the people responsible for the process. This work changes the migration conversation. Instead of asking which plugins can we convert? You ask which business outcomes still need automation? That is a better question. Now you can prioritize. Start with pain. Automation causes failures, delays, support work or manual chasing. Then look at change frequency. A rule that changes every quarter may suit a more visible automation model than a stable calculation untouched for years. Consider risk. A process tied to sensitive data, revenue decisions or compliance needs a careful path. Finally, consider technical fit. Some automation belongs outside the record transaction. Some does not. Some code should remain because replacing it creates more risk than value. After the inventory, every item needs a category. Not a target tool yet. A category. Only then can you choose what changes, what stays and what should disappear. A safer migration path from custom automation. Don't begin with the most dangerous plugin. Begin with the one that changes often. Look for automation that crosses systems. A process that updates dynamics, sends an approval, creates a task and notifies a team. That is usually a better first move. The boundary is easier to see. And the business already feels the cost of every change. Choose something important enough to prove the model. But not so central that one mistake stops the company. A recurring approval root works well. A customer follow-up process can work too. So can a notification process that depends on dynamics data and needs action in teams or outlook pick work where the process changes more often than the data model. That is where a visible automation layer earns its place fastest. Before building anything, document the current behavior. Not the intended behavior, the current behavior. What does the automation produce? Which records change? Which messages send? Which systems receive data? What exceptions already exist? A process may skip approval for certain account types. It may root requests differently by region. It may retry an external call after failure. It may depend on a field updated by another customization. Write that down, then document permissions. Which identity runs the current automation? What records can it read? What data can it change? Which external service permissions does it use? A replacement flow cannot safely reproduce the outcome if nobody understands the authority behind the old process. Dependencies need the same attention. A custom plug-in may publish a value that another integration expects. Script may set a field that triggers later work. A background process may rely on a status being written in a specific sequence. The old automation may contain behavior the business never asked for directly, but other systems still expect. That is why migration needs evidence. Not assumptions. Once the behavior is understood, build the replacement in development. Build it through a solution. Bring in the flow. Bring in the connection references. Bring in the environment variables. Keep the process components together. The replacement should not begin as a personal flow that someone plans to organize later. Later usually means after it becomes important. Give it the right structure from the first version. Use controlled configuration. Use the right identity model. Name the assets clearly. A migration is not just moving logic from C-Port into a visual designer. It is moving the process into an operating model that can support change. Then test it beside the existing process. Do not switch off the old automation on the day the new flow is built. Use controlled records. Create known scenarios. A standard request. An exception. A rejected approval. A delayed response. A record with missing information. That's what both paths do. Compare the result. Did dynamics receive the same outcome? Did the right person receive the right message? Did the external system get the correct data? Did the exception root behavior as expected? This parallel period matters because it exposes the details nobody remembered to document. Maybe the old plug-in normalized a value before sending it. Maybe it skipped a specific record type. Maybe it handled an integration timeout in a way the team only notices under load. Those discoveries are useful. They do not mean the migration failed. They mean the team found the real process before retiring the old automation. Keep the comparison controlled. You don't want both systems creating duplicate tasks or sending duplicate approvals to real users. Use test records. Use a test queue. Use a dedicated mailbox. Where needed? Configure one path to observe without performing the live action. The aim is proof. Not disruption. When the new process behaves correctly, release it as a managed package. Move the tested solution into production with the right configuration mapped for that environment. Once the release, no which version entered production, then monitor the runs. Watch failures. Watch retries. Watch approval delays. Check the records created or updated by the flow. Talk to the people who use the process. Technical success is not enough. If the seller receives a confusing message or an approver, lacks the context to decide. Only retire the old code when the replacement has earned that decision. Not when the flow first saves successfully. Not when the first test passes. Retire it after the production process works. The team can operate it. And the business owner accepts the result. Then remove the old path deliberately. Document the retirement. Confirm that no integration still depends on it. Otherwise, you risk running two sources of truth. This approach moves carefully without becoming slow. You start where change hurts. You build with the right structure. You test against the actual behavior. Then you release with evidence. But low code can create its own mess when teams skip those disciplines. The team model, business owns intent. IT owns guardrails. The process owner owns the intent. Not the flow, not the connector. The intent. Design what outcome the process needs to produce along with the rules and the exceptions. When an approval route changes, the process owner decides why. They confirm the policy if an account type should skip a review. And when an escalation needs a new recipient, they own that decision. This changes the conversation. Instead of telling IT, build what we asked for. The business takes responsibility for what the process should do. That responsibility cannot sit inside a technical backlog. The backlog can implement a request, but it cannot decide whether the request still makes business sense. So makers take that intent and turn it into automation. They build within an approved environment using approved connectors, following the delivery path for their type of work. That doesn't turn every maker into a developer. It gives them a clear place to work. A low-risk team process can move quickly. A production process follows a stronger path. The maker doesn't need to guess which rules apply. The operating model already answers that. IT owns the guardrails around the work. Identity. Data policies. Release discipline. Monitoring. Support routes. They stay with IT because they cross individual processes. So one team might build an approval flow, another builds a service escalation, and a third automates finance notifications. Each team knows its own outcome. It sees the shared platform underneath. Which identities run unattended work, which connectors can work with customer data. How do solutions move into production? Who sees a failed run? Where does a maker go when a connection breaks? Those are platform questions, and they meet consistent answers. Without that consistency, every team creates its own approach. One process uses a personal account, while another uses an un-reviewed shared login. One team tests changes another at its production directly. One flow sends failure alerts, another fails quietly. The automation may work today, but the organization cannot operate it as a system. I'd prevent that drift. Not by taking every build away from the business, but by defining the safe path before the business needs it. Developers still matter. They matter at the true code boundary. A developer handles work that needs controlled server-side execution, heavy processing, specialist integration work, or reusable components beyond what a flow should carry. That is not a fallback rule. It is a focused rule. Developers should not spend weeks turning ordinary routing rules into hidden code. Their time belongs where code gives the organization something the platform cannot provide cleanly. A narrow real-time validation. A performance-sensitive operation. A reusable component needed across several processes. A complex integration contract. That division improves both sides. The business stops waiting for developers to change ordinary process rules. The developer stops becoming the default owner of every small automation request. And I'd stop trying to govern work through approval meetings alone. Review should follow risk. Not job title. A business maker can build a safe internal process. A professional developer can create a risky integration. Neither title tells you enough. Look at the data, the process impact, and the identity involved. Check the systems. And consider what happens if the automation fails. A reminder flow for one team needs a different review from a process that updates customer records and triggers financial approval. The maker's title does not change that. The risk does. This is the team model behind scalable automation. Business owns what should happen. Makeers build the process within the defined boundaries. It keeps the platform safe and operable. Developers take the technical work that genuinely needs code. Then review follows the effect of the automation, not the person who created it. That model changes the executive decision too. Because the question is no longer whether to fund more custom development. It is whether the organization wants automation capacity to remain trapped inside a developer queue. A 90 day reset for dynamics automation. Don't start with the platform rebuild. Start with 30 days of visibility. Find the automation already running. List the plugins, scripts, flows, classic workflows, and integrations. Then identify the gaps. Who owns each process? Who can support it? Which identity runs it? Which automation has no current business owner? You're not fixing everything yet. You're finding the work your organization already depends on. That list changes the conversation quickly. Some automations will have clear owners and stable behavior. Others will reveal a different problem. Nobody knows why they run, who can change them safely or where the credentials sit. That is your starting point. In the next 30 days, define the operating rules. Create the environments needed for development, testing, and production work. Set the solution structure. Define which connectors can work together through DLP policy and how unattended automation uses identity. Then decide what belongs in a personal environment, what belongs to a team, and what qualifies as production automation. Keep these rules short. People need to use them. A maker should know where to build. The process owner needs to know who approves a change. And the support team should know where to look when something fails. The aim isn't paperwork. It's removing uncertainty before more automation appears. In the final 30 days, prove the model with one process. Pick a process that changes often and crosses systems. Maybe dynamic triggers an approval, teams notifies the right person and the outcome returns to the record. Build it in a solution with the right connection references and controlled configuration. If you've tested it before production, then release it through the path you defined. That one process gives the team evidence, not a slight deck evidence. You can see whether releases move faster, failure ownership is clear, and approvals wait less time. And you can see how much support effort disappears when the process has a visible structure. Measure those things. Release time. Failure rate. Approval delay. Support effort. Don't measure activity. Measure whether the operating model reduces friction around real work. Then publish the decision framework before demand expands. People will ask whether their process needs a flow, a low-code plug-in custom code, or no change at all. Give them a clear route before every new request becomes another architecture debate. Because demand will expand, it always does. Once people see that dynamics can trigger work across the tools they already use, they won't stop asking for automation. The question is whether those requests enter a system with ownership, boundaries, and clear choices. Or whether they become the next collection of hidden dependencies. That is the structural shift.

← Power Platform Governance Without Killing Innovation: SecuriInternal Developer Platforms (IDPs) - Simply Explained →