The Dataverse plug-in execution pipeline
By Emil Björk · Microsoft business apps consultant, Gothenburg
How Dataverse executes plug-ins — stages, pre/post images, transactional scope, and how multiple plug-ins interact on a single operation.
When an external call modifies a Dataverse record, multiple plug-ins, workflows, business rules, and platform logic may fire. Understanding the execution pipeline — the order and scope in which these run — is essential for any developer writing plug-ins or debugging behaviour that seems unpredictable.
The five stages.
- Stage 10 — Pre-validation — outside the database transaction. Used for early gates, custom auth, plugin-level redirects.
- Stage 20 — Pre-operation — inside transaction, before platform DB write. Modify the incoming target before commit.
- Stage 30 — Platform operation — the database write itself.
- Stage 40 — Post-operation (in transaction) — inside transaction, after DB write but before commit. Effects can be rolled back on exception.
- Stage 50 — Post-operation (out of transaction) — after commit. Async by default; out of the user's transaction scope.
Each plug-in registers at a specific stage; only Stage 20 and 40 plug-ins can directly affect the operation's outcome.
Stage 10 specifics.
- Outside transaction.
- Can cancel the operation by throwing.
- Limited by what's not yet committed (record doesn't exist yet for Create).
- Useful for early validations that don't need transactional rollback.
Stage 20 — pre-operation, in-transaction.
- Inside transaction.
- Can modify the
Targetentity — changes flow to the DB write. - Can throw exception, rolling back.
- Most validation logic goes here.
Example use: enforce business rule that account category must match account type.
Stage 30 — platform operation.
- The DB write itself.
- Plug-ins do not register here.
- Triggers cascade behaviour (related records updates, indexes).
Stage 40 — post-operation, in-transaction.
- After DB write; before commit.
- The record exists; can read it back.
- Can modify related records as part of the same transaction.
- Exception still rolls back.
Example use: create a child record automatically when parent is created.
Stage 50 — post-operation, out-of-transaction.
- After commit.
- Async by default.
- Failures don't affect the original operation.
- Used for external integrations (call third-party API), audit logging, notifications.
For most "after creation, do this" scenarios, this is the right stage.
Sync vs async at Stage 50.
- Sync — runs in the same operation context but outside transaction; user waits.
- Async — runs in background job queue; user doesn't wait.
For external API calls, async preferred — user shouldn't wait on third-party responsiveness.
Pre and post images.
- PreImage — snapshot of the record before the operation. Available in Stages 20, 40, 50.
- PostImage — snapshot after. Available in Stage 40 and 50.
- Required for Update operations to compare before/after.
- Configured at registration time.
The image structure: choose which columns to capture. Capturing all is heavy; capture only what you need.
Plug-in registration parameters.
- Message — Create, Update, Delete, etc.
- Primary entity — which table.
- Filtering attributes — only fire when these columns change (Update only).
- Stage.
- Execution mode — Sync / Async.
- Deployment — Server / Offline / Both.
- Unsecure / secure configuration.
Multiple plug-ins same stage.
- All run sequentially.
- Order configured via "Execution Order" on the registration.
- Lower number runs first.
For deterministic behaviour, set execution order explicitly when multiple plug-ins on same event.
Recursion control.
- Each operation has a depth value.
- A plug-in modifying its own table triggers another invocation; depth increments.
- Default max depth = 8.
- Plug-in should guard:
if (context.Depth > 1) return;
Without guard, infinite recursion possible (or hits depth limit).
Transaction scope.
- Stages 20 and 40 in transaction; all changes atomic.
- Throwing exception rolls back everything.
- Stage 50 out of transaction; original committed before this runs.
For multi-record consistency, use Stage 40; for fire-and-forget, Stage 50 async.
Performance considerations.
- Sync plug-ins block the user's operation; keep fast (< 2 seconds).
- Heavy logic belongs in async Stage 50.
- Image data load — capturing many columns slows registration; tune.
Plug-in pipeline + workflows + business rules.
- Business rules — run client-side (and server-side for some).
- Real-time workflows — run server-side, similar to plug-ins.
- Plug-ins — code.
- Async workflows / flows — out-of-band.
All can fire on the same event; ordering matters.
Common pitfalls.
- Wrong stage. Validation at Stage 50 — too late.
- No image — Update plug-in can't see old values.
- Recursive plug-in — depth guard missing.
- Slow sync plug-in — user-facing slowness.
- Stage 10 cancel on Create — record doesn't exist; cascade behaviour unclear.
- Plug-in chains — cascading effects unpredictable; debugging hard.
Best practices.
- Comment the stage choice — future maintainers understand the rationale.
- Test all stages — what happens if your plug-in throws at each stage?
- Logging in plug-ins — for production diagnosability.
- Avoid cross-table updates in Stage 20/40 unless needed.
- Keep plug-in scope narrow — one logical responsibility per plug-in.
Strategic positioning
The pipeline is the foundation of all server-side Dataverse logic. Misunderstanding it leads to subtle bugs — race conditions, partial writes, missing data. Mastering it produces robust, maintainable extensibility. Invest in the model; the productivity gain is across every plug-in you'll write thereafter.
Related guides
- Dataverse plug-ins explainedHow Dataverse plug-ins work — pipeline stages, sync vs async, registration, debugging, and when to use a plug-in vs a Power Automate flow.
- Impersonation in Dataverse plug-insHow impersonation works in Dataverse plug-ins — running as the calling user vs system user, the SDK patterns, and the security implications.
- Low-code plug-ins in DataverseHow Dataverse low-code plug-ins let makers run server-side logic without C# — Power Fx, when to use them vs Power Automate vs traditional plug-ins.
- What is Microsoft Dataverse?Microsoft Dataverse is the relational data platform underneath Dynamics 365 CRM apps and Power Platform — what it is, why it's more than a database.
- Dataverse data model fundamentalsThe Dataverse data model — tables, columns, relationships, choices, security roles, and how it sits under Dynamics 365 and the Power Platform.
Browse every guide in Customer Engagement or just Dataverse platform.
Was this helpful?
Signals which guides land and which need work. No account, no comment box — corrections go through the contact page.
Spot something wrong or want a topic covered? Send a correction or a topic request — both are welcome.