The Dataverse SDK is not something you graduate from. A framework only earns its place when it removes recurring engineering cost without hiding the platform you still need to understand.
A Dataverse plug-in can be very small.
You implement IPlugin, read the execution context, do the work, register the step, and move on.
For a single internal plug-in, that can be exactly the right solution.
The interesting question starts later.
What happens when one plug-in becomes twenty? When multiple developers touch the same solution? When DEV, TEST and PROD no longer have exactly the same registrations? When every new plug-in starts by copying the same context, tracing, validation and registration patterns?
That is where teams usually start asking whether they need a framework.
The useful question is not:
Should every Dataverse project use a plug-in framework?
It is:
At what point does the cost of repeating the same engineering decisions become higher than the cost of adopting an abstraction?
That is what this article is about.
TL;DR
- Plain SDK is a valid architecture. A small, stable plug-in does not need a framework just because one exists.
- Frameworks start paying for themselves when repetition becomes delivery risk — more developers, more environments, more registrations, longer solution lifetime and a stronger need for repeatable tests.
- The real decision is who owns the conventions the SDK leaves open: each developer, your internal standards, or a framework.
What the Plain SDK gives you in 2026
The standard Dataverse plug-in model is still the foundation.
A plug-in is a class that implements IPlugin and executes because a registered Dataverse step connects that class to an event in the Dataverse execution pipeline.
Microsoft's supported model still revolves around:
-
IPlugin, -
IPluginExecutionContext, -
IOrganizationService, - plug-in assemblies and packages,
- message processing steps,
- images,
- filtering attributes,
- the Plug-in Registration Tool,
- Power Platform CLI,
- and Power Platform Tools for Visual Studio.
The first-party tooling around the SDK has improved considerably.
Power Platform CLI can initialize a plug-in project:
pac plugin init
and can import a plug-in assembly or package into Dataverse:
pac plugin push
The Plug-in Registration Tool is still supported and can be launched through:
pac tool prt
Power Platform Tools for Visual Studio can create, register, deploy, debug and profile plug-ins as well.
So the reason to adopt a framework in 2026 is not that Microsoft gives you no tooling.
It is also important to separate two concerns:
Getting plug-in code into Dataverse
≠
Defining exactly when and how it executes
An assembly can be present while the registration around it is still wrong.
That distinction becomes increasingly important as a solution grows.
A small plug-in may not need a framework
Imagine a plug-in with one responsibility:
On Account update, reject a change if a specific business condition is not satisfied.
A straightforward SDK implementation may be entirely reasonable:
public class ValidateAccountPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var context =
(IPluginExecutionContext)serviceProvider
.GetService(typeof(IPluginExecutionContext));
if (!context.InputParameters.TryGetValue("Target", out var targetValue))
return;
if (targetValue is not Entity target)
return;
if (target.LogicalName != "account")
return;
if (!target.Contains("name"))
throw new InvalidPluginExecutionException(
"Account name is required.");
}
}
There is nothing inherently wrong with this.
For a tiny project, adding another dependency, another execution model and another deployment convention may create more complexity than it removes.
Zero framework is a valid architecture.
A framework should have to justify itself.
Where the cost starts to appear
The SDK gives you platform primitives.
It deliberately does not prescribe the architecture of your whole solution.
That freedom is useful, but the team has to provide the missing discipline.
As the solution grows, the same categories of work tend to repeat.
Execution boilerplate
Every plug-in needs some combination of:
- execution context,
- target handling,
- pre/post images,
- organization services,
- tracing,
- configuration,
- stage/message checks,
- error handling.
A good team can centralize this themselves.
A less disciplined codebase gradually gets twenty slightly different versions of the same thing.
Validation mixed with execution
The SDK does not force you to separate:
Can this operation run?
from:
What should this operation do?
That separation is an architectural decision.
Without a convention, plug-in classes often accumulate both.
Registration lives somewhere else
The business code can be perfectly version controlled while the actual plug-in step still exists only as a Dataverse record.
That means the complete behavior is:
code + deployed registration
not just:
code
If registration is not reproducible, source control is only telling part of the story.
Environment drift
A common operational problem is not a broken DLL.
It is an environment that contains:
- an old step,
- a disabled step,
- different filtering attributes,
- a missing image,
- a different execution order,
- or a duplicate registration.
The application can compile successfully while DEV and PROD still behave differently.
Testing becomes inconsistent
Plain SDK code can absolutely be tested.
The SDK does not make code untestable.
But the team has to decide:
- what is isolated from the plug-in entry point,
- what gets mocked,
- whether pipeline behavior is simulated,
- whether anything is tested against real Dataverse,
- how test data is created and removed.
Again: freedom means the team owns the convention.
Five signals that an abstraction may start paying for itself
There is no plug-in count at which a framework suddenly becomes mandatory.
But there are useful signals.
1. You are repeating the same structure
If every new plug-in starts by copying another plug-in and deleting half of it, you already have an implicit framework.
It just lives in copy-paste.
At that point, formalizing the pattern can reduce variance.
2. Registration is part of delivery risk
If deployment requires someone to open the Plug-in Registration Tool and verify steps manually, registration has become part of your delivery process.
For a small solution, that may be acceptable.
For a team shipping frequently across several environments, it becomes an operational dependency.
3. The project needs repeatable tests
The value of reusable test infrastructure increases with the lifetime of the solution.
A plug-in that changes once a year can survive manual verification.
A business-critical implementation that changes every sprint benefits much more from repeatable regression tests.
4. More developers need to understand the same codebase
Frameworks can reduce local creativity.
That sounds negative, but in a large codebase it is often useful.
If every plug-in has the same shape, a developer can move between features without first reverse-engineering the author's preferred pattern.
5. The solution will live for years
The longer a solution lives, the more expensive inconsistency becomes.
The first plug-in is cheap.
The fiftieth deployment, third developer and fourth environment are where architectural decisions start compounding.
What a framework should actually buy you
A framework should not be measured by how many classes it adds.
It should be measured by which recurring problems disappear.
For a Dataverse plug-in project, useful framework responsibilities can include:
| Problem | Plain SDK | What a framework can add |
|---|---|---|
| Plug-in execution | Platform primitives | Consistent execution pipeline |
| Validation | Team convention | Explicit validation lifecycle |
| Step registration | PRT / VS tooling / custom automation | Registration defined in code |
| Environment consistency | Team/CI responsibility | Deterministic registration synchronization |
| Diagnostics |
ITracingService + custom patterns |
Standard structured logging |
| Testing | Build your own approach | Reusable unit/integration test foundation |
| Project structure | Team decision | Consistent templates and conventions |
| Onboarding | Learn project-specific patterns | Predictable project shape |
A framework does not remove the SDK.
It organizes how the team uses it.
There is also an emerging AI-assisted development benefit to making those conventions explicit. Small task-sized units, code-defined registration and executable tests give coding agents clearer boundaries and feedback than a large plug-in class whose behavior has to be inferred. Pillaro explicitly treats this as part of its AI-Ready Standard — not as autonomous development magic, but as a way to make the codebase easier for both developers and AI tools to reason about.
A concrete example: the Pillaro approach
Pillaro is one possible answer to these problems.
Disclosure: I maintain it.
It is open source under Apache-2.0, free to use in commercial projects, and production-proven. The framework's first production adopter was Seyfor, where it has been deployed in enterprise Dynamics 365 and Power Platform solutions.
Starting a new solution does not have to mean wiring the framework, testing package and early-bound tooling by hand. Pillaro ships official starter templates for both dotnet new (CLI, VS Code, Visual Studio) and a Visual Studio VSIX template, generated from the same shared source so both produce an identical project structure.
For the fastest path to a running task-based plug-in project:
dotnet new install Pillaro.Dataverse.PluginTemplate.DotNetNew
dotnet new pillaro-dataverse-plugin-dotnet -n MySolution
That is often the practical answer to "I just need one plug-in fast" — you get the task/validation structure, code-defined registration, testing package and early-bound tooling already wired, instead of assembling them by hand.
Pillaro is also listed in Microsoft Learn's Community Tools for Microsoft Dataverse catalog and is published in Microsoft Marketplace. The Marketplace offer installs the Dataverse-side runtime used by the framework, while the C# framework itself is consumed as a NuGet package.
Microsoft Learn explicitly notes that community tools are supported by their publishers rather than by Microsoft.
Microsoft Learn listing · Microsoft Marketplace
The framework uses a task-based model where validation and execution are explicit phases:
A task follows a consistent lifecycle:
public class MyFirstTask(
IServiceProvider serviceProvider,
TaskContext taskContext)
: TaskBase<Logic.Task>(serviceProvider, taskContext)
{
protected override ICompleteValidation AddValidations(
IBasicModeValidation validator)
{
return validator
.WithMode(PluginMode.Synchronous)
.WithStage(PluginStage.Preoperation)
.WithMessages(["Create"])
.ForEntity(ContextEntity.LogicalName);
}
protected override void DoExecute()
{
// Business logic
}
}
The plug-in then registers that task for runtime execution:
RegisterTask<MyFirstTask>(
PluginStage.Preoperation,
["Create"],
Task.EntityLogicalName,
PluginMode.Synchronous);
Deployment metadata is declared separately:
public override void Register(IPluginRegistration registration)
{
registration
.OnCreate<Task>("8c46d6e6-3c25-4b9d-9264-6c0d02b4d2f1")
.PreOperation()
.Synchronous()
.Rank(1);
}
That separation is intentional.
RegisterTask(...) tells the runtime which task to execute.
Register(IPluginRegistration registration) tells deployment tooling which Dataverse registration should exist.
The stable step ID gives the deployment model a persistent identity for the step, while the deployment tooling synchronizes the declared registration with Dataverse.
Pillaro also provides functional testing infrastructure that runs against a real Dataverse environment with deployed plug-ins and cleans up tracked test data afterwards.
That is one design choice.
Other frameworks make different choices.
The point is not that this is the only valid architecture. It is an example of what it means for a framework to own repeated conventions on purpose.
What a framework should not do
A framework can solve real problems and still be the wrong choice.
There are several failure modes worth watching for.
It should not hide Dataverse from you
A developer using a framework still needs to understand:
- pipeline stages,
- execution depth,
- transactions,
- images,
- filtering attributes,
- synchronous vs asynchronous execution,
- recursion,
- security context,
- service calls.
If the abstraction makes those concepts invisible, debugging becomes harder rather than easier.
It should not own everything just because it can
In 2026, Microsoft already provides first-party tooling for large parts of the development lifecycle.
For example:
Plug-in project → pac plugin
Typed model code → pac modelbuilder
Solution lifecycle → pac solution
PRT → pac tool prt
A framework does not need to reimplement every Power Platform CLI feature.
Sometimes the better design is to integrate with the Microsoft tool instead of competing with it.
Pillaro follows that approach for early-bound generation: its project tooling prepares a local Tools/EarlyBound/ workflow, but the actual generator underneath is Microsoft's pac modelbuilder.
It should not make leaving impossible
A healthy abstraction sits on top of understandable platform concepts.
You should be able to explain what the framework is doing in Dataverse without treating it as magic.
That keeps migration possible and reduces long-term dependency risk.
When Plain SDK is probably the better choice
There are situations where I would deliberately stay with the SDK.
One or two small plug-ins
If the entire solution contains a few simple steps, there may be no recurring cost worth abstracting.
You are learning Dataverse plug-in execution
Learning the raw SDK first is useful.
Understanding IPluginExecutionContext before wrapping it gives you a much better mental model when something eventually goes wrong.
Third-party dependencies are restricted
Some customers or regulated environments do not allow additional runtime libraries without a review process.
The plain SDK may be the simplest acceptable option.
The existing codebase is stable
If a mature project has working deployment, documented conventions and little ongoing development, introducing a framework can create migration cost without enough return.
Your architecture is already standardized internally
A strong engineering team may already have:
- a plug-in base,
- registration automation,
- test infrastructure,
- logging,
- templates,
- CI/CD.
At that point you may already have the useful parts of a framework — just internally.
Replacing them with a public framework is not automatically an improvement.
When a framework becomes easier to justify
The case gets stronger when several of these are true:
- many plug-in steps are under active development,
- several developers work in the same solution,
- deployment spans multiple environments,
- registration drift has already caused incidents,
- business logic is expected to evolve for years,
- automated regression testing matters,
- onboarding speed matters,
- the same architecture is reused across multiple customer projects.
Notice what is missing from that list:
"The plug-in has a lot of lines of code."
Line count is not the main issue.
Repeated engineering decisions are.
The decision I would make
For a small, isolated plug-in, I would start with the SDK.
For a long-lived solution, I would make one explicit decision early:
Who owns the conventions that the SDK intentionally leaves open?
There are three reasonable answers:
1. The individual developer
2. The team / internal standards
3. A framework
The dangerous answer is:
Nobody — we'll decide separately every time.
That is where accidental architecture starts.
A practical decision checklist
Before adding a framework, ask:
- What recurring problem are we solving?
- Can Microsoft tooling already solve it?
- Can a small internal convention solve it?
- Does the framework make deployment more reproducible?
- Does it make plug-in behavior easier to understand?
- Does it improve testability in the way we actually test?
- Will a new developer understand the architecture faster?
- Can we still reason about the underlying Dataverse execution model?
- What happens if the framework is no longer maintained?
- Is the adoption cost lower than the repetition cost over the expected lifetime of the solution?
If those questions have good answers, the abstraction may pay for itself.
If they do not, the SDK is still there — and it is still a perfectly valid choice.
What comes next
In Part 3, I will compare two actively maintained frameworks with very different design centers:
Pillaro and XrmFramework.
Not to pick a winner, but to look at what each one chooses to own: execution structure, typed models, deployment, debugging, testing and developer tooling.
If you want to try the approach on a real project, Pillaro is Apache-2.0 licensed and free for commercial use. The GitHub repository contains the getting-started guide, NuGet packages, templates, deployment documentation and testing stack. It is already used in production, with Seyfor documented as the first production adopter.
Sources
- Microsoft: Use plug-ins to extend business processes
- Microsoft: Register a plug-in
- Microsoft: Power Platform CLI — pac plugin
- Microsoft: Power Platform CLI — pac tool
- Microsoft: Power Platform developer tools
- Microsoft: Power Platform Tools for Visual Studio
- Pillaro Dataverse Plugin Framework
- Pillaro README — production adoption, Apache-2.0 license and AI-Ready Standard
- Microsoft Learn: Community Tools for Microsoft Dataverse — Pillaro
- Microsoft Marketplace: Pillaro Dataverse Plugin Framework
- Pillaro Getting Started
- Pillaro Plugin Registration API
- Pillaro Testing Overview
Disclosure: I maintain Pillaro. The goal of this article is not to argue that every Dataverse project needs a framework. It is to make the trade-off explicit.

Top comments (0)