Dataverse plugins are one of the most powerful and common tools in the Microsoft Dynamics / Power Apps ecosystem. They’re the right fit when synchronous logic or server-side validation needs to take place. Think validate user input before the record can be saved’ or ‘reliable field calculation when a user or a process updates a record’. When registering a Dataverse plug-in step, two of the most important settings are Stage of Execution and Execution Order.
Here’s what they do:
- Stage determines when the plug-in runs during the Dataverse operation.
- Execution Order determines which plug-in runs first when multiple steps are registered in the same stage.
Things get tricky when these concepts aren’t understood by the developer and can cause hard to diagnose problems.
The Dataverse Execution Pipeline
A Dataverse operation moves through several stages.
| Stage | Number | When It Runs | Common Uses |
|---|---|---|---|
| PreValidation | 10 | Before the main operation, usually before the database transaction | Rejecting invalid input before a form can be saved |
| PreOperation | 20 | Before the main operation and inside the transaction | Changing values before they are saved (performing calculations that will exist inside the original save transaction) |
| Main Operation | — | Dataverse performs the requested operation | Managed internally by Dataverse |
| PostOperation | 40 | After the main operation | Creating related records or performing after-save logic such as deletes |
Microsoft allows custom plug-in steps to be registered in PreValidation, PreOperation, and PostOperation. The main operation can’t be touched.
PreValidation
Use PreValidation when your plug-in needs to determine whether the operation should be allowed.
For example, you might prevent an opportunity from being closed when required approval records are missing. Or maybe you didn’t want to make a field required to create the Opportunity originally, but that field needs data before the opportunity can be closed. A PreValidation plugin is perfect for this.
Because PreValidation occurs before the database transaction begins, cancelling the operation here is more efficient than cancelling it later and forcing Dataverse to roll back the transaction. One important exception is when the operation was triggered by another plug-in already running inside a transaction.
Good uses include:
- Validating business rules
- Blocking invalid deletes
- Preventing unauthorized state changes
- Returning a clear validation message to the user
PreOperation
Use PreOperation when you need to change data before Dataverse saves the record.
The Target entity contains the values being submitted. You can modify these values directly:
Entity target = (Entity)context.InputParameters["Target"];
target["new_calculatedvalue"] = 100;
You generally should not call service.Update(target) in a PreOperation plug-in. Changing the Target directly allows Dataverse to include your changes in the original operation without starting another Update request. Microsoft specifically recommends PreOperation when changing values included in the message. This will allow the plugin to execute faster than if the same logic was run PostOperation and service.Update(target) was needed.
Good uses include:
- Setting default values
- Calculating values before save
- Normalizing text
- Populating lookup fields
- Applying server-side business rules
PostOperation
Use PostOperation when the main Dataverse operation must finish before your logic can run.
For example, after creating an account, you might create related contact records that require the new account ID.
Synchronous PostOperation steps still run inside the database transaction. An exception can therefore cause the original operation and related changes to roll back. Updating the same record again during PostOperation can also trigger another Update event, potentially causing recursion.
Good uses include:
- Creating related records
- Using the ID of a newly created record
- Performing logic that requires the completed operation
- Modifying output parameters returned to the caller
Asynchronous PostOperation
Asynchronous plug-ins can only be registered in PostOperation.
They are placed into the asynchronous system job queue and execute after the main record operation completes. Because they run outside the original database transaction, they cannot cancel or roll back that operation.
Async plug-ins are useful for work that should not make the user wait, such as:
- Sending data to an external system
- Performing longer-running calculations (keep in mind, we still have a 2-minute timeout on these)
- Creating non-critical supporting records
- Starting downstream processes
Do not depend on multiple asynchronous plug-ins running in a particular order. Microsoft states that execution order between asynchronous plug-ins is not guaranteed.
How Execution Order Works
Execution Order controls the order of steps registered for the same message and stage.
Lower numbers run first.
For example, suppose three synchronous plug-ins are registered on the Account Update message:
- PreOperation — Execution Order 10
- PreOperation — Execution Order 20
- PostOperation — Execution Order 5
The execution sequence will be:
PreOperation: Order 10
PreOperation: Order 20
Dataverse main operation
PostOperation: Order 5
The PostOperation step does not run first just because its execution order is lower. Stage takes priority over execution order.
Execution Order only sorts plug-ins inside the same stage. Microsoft also warns that when multiple steps have the same execution-order value, their actual order is not guaranteed.
Recommended Execution-Order Convention
Avoid leaving every plug-in at the default execution order.
A simple convention is to leave space between steps:
10 – Initial validation or preparation
20 – Main custom logic
30 – Dependent or follow-up logic
Leaving gaps makes it easier to insert another step later without renumbering everything.
When one plug-in depends on another, give them distinct execution-order values and document the dependency. Better yet, avoid tightly coupling separate plug-ins unless the separation provides a clear benefit! Developers have different opinions on this, however. Having multiple smaller, simpler plugins can make it easier to debug each piece of logic. But it also means your logic is spread out across multiple registered plugins, each with its own execution order. That adds some overhead. A good rule of thumb is to be consistent with whichever route you decide to go.
Simple Rule of Thumb
Use:
- PreValidation to decide whether the operation should continue.
- PreOperation to change the data being saved.
- PostOperation when the operation must finish first.
- Asynchronous PostOperation for slower or non-critical processing.
- Execution Order to control sequencing within the same stage.
Thanks for reading!