Almanac
Microsoft/dataversePower Platform

Consultant KB for Microsoft Dataverse, the data layer under Dynamics 365 and the Power Platform: data model, security model, business logic, APIs and integration, search and queries, analytics and Fabric, ALM and solutions, administration, governance and compliance, and Dataverse as an agent data platform, plus cross-cutting decision guides. Implementation notes, configuration decisions and the gotchas that bite on real projects. Populated by the daily author agent from the Dataverse release plans, docs repo and product blog, plus the author's own consultant notes.

feature-plug-ins.mdv1 · history
CurrentApplies to MakerUpdated last monthSource Microsoft Learn

What it does

A .NET Framework class implementing IPlugin, compiled into an assembly, uploaded to Dataverse and registered against a message and table combination in the event pipeline. When that event occurs, your code runs — able to cancel the operation, change the data in flight, call other operations, or talk to external systems.

Key facts

  • Four pipeline stages: PreValidation (before the main operation and before the security check, outside the initial transaction), PreOperation (before the main operation, inside the transaction), MainOperation (internal use only, except for custom APIs and custom virtual table data providers), and PostOperation (after the main operation, inside the transaction).
  • Asynchronous steps can only be registered on PostOperation, and they run outside the database transaction via the async service.
  • There's a hard 2-minute limit for a Dataverse message operation to complete, covering the operation itself plus all registered synchronous and asynchronous plug-ins. Exceed it and you get a TimeoutException and a full rollback. Microsoft's own recommendation is to keep an individual plug-in under 2 seconds.
  • CPU, memory and handle limits also apply. Breach them and Dataverse kills the process; the next execution runs normally.
  • Plug-ins run in the sandbox. The isolation mode and location options in the registration tool are on-premises artefacts — in the cloud always accept Sandbox and Database.
  • Service protection limits don't apply to operations originating inside a plug-in, because the sandbox doesn't use the public API endpoints. The compute time still accrues to the request that triggered it.
  • Entity images are supported on a fixed list of messages only: Assign, Create, Delete, DeliverIncoming, DeliverPromote, Merge, Route, Send, SetState and Update. No pre-image on Create, no post-image on Delete, and post-images only on PostOperation steps.
  • The assembly and each step are separate solution components. Adding the assembly to a solution does not bring the steps with it.
  • Secure Configuration data isn't included when you export a solution.
  • Microsoft no longer allows you to unregister or disable out-of-the-box system plug-ins and steps.

When to use / skip

Use a plug-in when the logic must be enforced regardless of how the data arrived, when it needs to run inside the transaction, or when performance matters enough that a flow's latency is unacceptable. Plug-ins can do everything a workflow can and more, which is precisely why they get overused — the disadvantages are real: you need a developer to change anything, and a badly written one degrades the whole environment for everyone. Before writing one, check whether a formula column, a business rule, a custom API with no logic, a flow, or a webhook to an Azure Function does the job. If the answer to "why not a flow?" is only "flows feel slow", that's usually not enough.

Configuration decisions

  • Stage: PreValidation to cancel cheaply, PreOperation to modify the incoming data, PostOperation to react. Cancelling in PreOperation rolls back a transaction and costs real performance.
  • Synchronous or asynchronous, and if there's any doubt, asynchronous — better responsiveness and better scalability.
  • Which columns go into the pre-image and post-image. The default is all columns; do not accept it.
  • Filtering attributes on Update steps, so you're not running on every save. Never include the primary key, which is always present and negates every other filter.
  • Execution order, explicitly. Two steps sharing a stage and the same order value execute in an order Dataverse doesn't guarantee.
  • Whether the step runs as the calling user or an impersonated one, which is a security decision, not a plumbing one.

Gotchas

  • Assembly version numbers change behaviour on solution import. Bumping build or revision is an in-place upgrade and steps follow automatically; bumping major or minor makes it a different assembly, and existing steps keep pointing at the old version until you repoint them by hand.
  • An unhandled exception at any synchronous in-transaction stage rolls back everything, including work done by other people's plug-ins in the same pipeline.
  • Update plug-ins can be called twice for certain specialised operations. If you're seeing duplicate side effects, that's the first thing to check, not your own code.
  • Registering on the Execute message technically works and is a very effective way to bring an environment to its knees, because every operation calls it.
  • If you register a plug-in on a message that also has a bulk equivalent, be careful about duplicating logic across the single and multiple versions of the event — Dataverse won't stop you applying it twice.
  • The "Message size exceeded when sending context to Sandbox" error appears around 116.85 MB of request payload, and only when a plug-in is registered. Large bulk writes hit this and the cause is never obvious from the error.

Consultant notes

  • Establish early who is allowed to write plug-ins and where they're source-controlled. Undocumented sandbox code found during a support handover is the classic Dataverse legacy problem.
  • Push back on "make it a plug-in so it's fast" as a design principle. Every synchronous plug-in is a tax on every save of that table, paid by every user forever.
  • Ask for the plug-in analytics dashboard in the admin centre to be reviewed monthly. Average execution time and failure counts are free and nobody looks at them.
  • Warn the client that a plug-in is a code asset with a maintenance cost. If they can't name who will maintain it in two years, take the requirement somewhere else.

Worth another look after any major solution upgrade, and whenever someone reports intermittent timeouts on a busy table.

Was this accurate?