Dataverse plug-ins vs Power Automate for integrations: when to use which

By Emil Björk · Microsoft business apps consultant, Gothenburg

The decision between a C# plug-in and a Power Automate flow for integration logic in Dataverse — transactions, latency, throughput, ownership, and the cases where each is clearly wrong.

Updated 2026-09-02

Every Dataverse project reaches the moment where something needs to happen when a record changes, and someone has to decide whether that something is a plug-in or a flow. Both can call external systems, both can update Dataverse, and both have partisans. The decision is not about skill or taste. It is about where the logic needs to run relative to the database transaction, how fast it must be, how much of it there is, and who will own it in three years.

The one difference that decides most cases

A plug-in registered synchronously runs inside the Dataverse transaction. If it throws, the user's save fails and nothing is written. A Power Automate flow runs after the transaction has committed, on its own schedule, with no ability to stop the save. That single fact sorts a surprising amount of integration logic.

If the external system must agree before the record is allowed to exist (a credit check before an order is created, a tax engine validation before an invoice is saved, an address validation before an account is committed), it is a synchronous plug-in. Nothing else can veto the save. See the plug-in execution pipeline for what runs when.

If the external system just needs to hear about the change (notify a shipping system, push a contact to a marketing tool, log to a warehouse), it is a flow, or an asynchronous plug-in, or better still an event on a queue. Blocking the user's save while a marketing API answers is a design error, however it is implemented.

When plug-ins win

  • Veto logic as above.
  • Latency-sensitive updates that the user expects to see immediately on the same form, such as a calculated field derived from an external rate.
  • High volume. Thousands of record changes an hour will exhaust Power Automate's run and action limits and cost real money per run. A plug-in costs nothing per execution.
  • Complex logic that is painful to express in a visual designer: recursion, heavy string handling, anything with more than a handful of branches.
  • Impersonation and elevated operations that need to run as a specific user or bypass a user's permissions in a controlled way; see impersonation in plug-ins.

When Power Automate wins

  • Fire-and-forget notifications to external systems where a delay of seconds to minutes is fine.
  • Connector-heavy work. If the job is "put a row in SharePoint, send a Teams message, and create a ticket in ServiceNow", the connectors exist and the flow is done in an hour. The equivalent plug-in involves three authentication schemes and three SDKs.
  • Approval and human-in-the-loop processes. Plug-ins cannot wait for a person.
  • Scheduled work on a cadence rather than on an event. Plug-ins do not have timers.
  • Ownership by makers. If the team that will maintain this is functional rather than developer, a flow they can read beats a plug-in they cannot.

The trap in the middle

Asynchronous plug-ins occupy the space between the two: code, but off-transaction, executed by the async service with retries. They are the right choice for post-commit logic that is too heavy or too frequent for flows, and the wrong choice when what you actually want is a durable queue, because the async service is not one. For anything that crosses a system boundary and must not be lost, the honest pattern is plug-in writes to a Service Bus queue or an outbox table, and a consumer does the integration; see the outbox pattern with Service Bus.

The other trap is calling an external HTTP endpoint from a synchronous plug-in "just this once". The two-minute execution limit, the sandbox restrictions, and the fact that a slow third party now slows every user save mean this should be a last resort with a tight timeout, not a habit.

Low-code plug-ins

Dataverse also offers low-code plug-ins written in Power Fx, which run in the transaction like C# plug-ins but are authored by makers. They cover simple validation and calculation well and are not yet a serious integration tool; the external-call story is through connectors and is limited. Treat them as a third option for the light end of the plug-in use cases, not as a replacement for either.

Cost and licensing

Flows consume Power Platform request limits and, depending on licensing, per-flow or per-user entitlements. Plug-ins consume Dataverse API request allowances but no per-run charge. At low volume the difference is invisible; at high volume flows become the expensive option and the throttled one.

Testability and ALM

Plug-ins have unit tests, source control, and a build pipeline, if the team sets them up, and are deployed in solutions like anything else. Flows live in solutions too, can be exported and imported, but testing is largely manual and version history is thin. A regulated environment that needs auditable change control tends to lean plug-in for anything critical. See solution import and export pipelines.

A working rule

Inside the transaction, or high volume, or complex: plug-in. After the transaction, connector-shaped, human-involved, or maker-owned: flow. Crossing a system boundary with data that must not be lost: neither directly; queue it. If two people on a project disagree, the disagreement is almost always because they have not agreed which of those buckets the requirement is in.

Stability verdict

Both tools are mature and neither is going anywhere. The unstable part is the boundary: teams that build integrations as flows because it was quick, then hit limits, then rewrite as plug-ins, then find they wanted a queue. Decide the bucket first. For the underlying mechanics, see Dataverse plug-ins explained and Power Automate connectors for Dynamics 365.

Further reading

Related guides

Spot something wrong or want a topic covered? Send a correction or a topic request — both are welcome.