XrmFramework and Pillaro both try to reduce friction in Dataverse plugin development. They do it from different starting points: one optimizes for a broad productivity stack, the other for an explicit task lifecycle, deterministic registration and real-environment testing.
This is the comparison in this series where the tools really do overlap.
Both XrmFramework and Pillaro are actively maintained Dataverse development frameworks.
Both move plugin registration closer to code.
Both provide project structure and deployment tooling.
Both try to make Dataverse development more predictable than repeating raw SDK plumbing in every project.
But they are not trying to build the same product.
That makes a simple feature-count comparison less useful than it first appears.
The better question is:
What development model does each framework want your team to adopt?
Disclosure: I maintain Pillaro. I have tried to describe XrmFramework from its current repository and documentation, including the parts where it is clearly broader or more mature.
Pillaro is listed in Microsoft Learn's Community Tools for Microsoft Dataverse catalog and is published in Microsoft Marketplace. The Marketplace offer installs the Dataverse-side managed solution the framework depends on, including the model-driven app for configuration and diagnostic logs; development teams consume the C# framework through NuGet.
These listings improve discoverability and distribution, but the Microsoft Learn catalog explicitly states that community tools are supported by their publishers rather than by Microsoft.
Microsoft Learn listing · Microsoft Marketplace
The short version
If you want the comparison in one paragraph:
XrmFramework is the broader productivity platform. It includes typed model tooling, a service-oriented architecture, declarative plugin registration, Custom API deployment, Roslyn analyzers, project templates, web-resource deployment utilities and a live remote debugger.
Pillaro is narrower and more opinionated around the plugin execution lifecycle. It centers development around small tasks with explicit validation and execution phases, stable registration identity, deterministic deployment, structured diagnostics and integration tests that run against a real Dataverse environment.
Neither design is universally better.
They optimize different things.
XrmFramework's design center: remove Dataverse development friction
The XrmFramework README describes its goal as making Dynamics 365 / Dataverse development feel more like modern .NET.
That is visible across the project.
Plugin steps are declared in code
A plugin inherits from the framework Plugin base class and defines steps in AddSteps():
protected override void AddSteps()
{
AddStep(
Stages.PreValidation,
Messages.Create,
Modes.Synchronous,
AccountDefinition.EntityName,
nameof(Method1));
AddStep(
Stages.PostOperation,
Messages.Update,
Modes.Synchronous,
AccountDefinition.EntityName,
nameof(Method2));
}
Additional registration metadata is attached to the target method with attributes:
[PreImage(AccountDefinition.Columns.Name)]
[PostImage(AccountDefinition.Columns.Name)]
[FilteringAttributes(
AccountDefinition.Columns.Name,
AccountDefinition.Columns.AccountNumber)]
[ExecutionOrder(100)]
public void Method(...)
{
}
Deployment then registers those steps in Dataverse.
Strongly typed models are a major part of the experience
XrmFramework 3.1+ makes .table files the source of truth for Dataverse table metadata. Typed table, column and option-set definitions are generated at compile time by a Roslyn source generator.
Binding models can be described in .model files and generated the same way, including the mapping code between Dataverse entities and typed models.
The files can be produced and maintained through XrmFramework tooling, including the Definition Manager and the xrmframework CLI.
The design goal is clear:
reduce magic strings and make Dataverse metadata refactor-friendly.
The 3.1 line is a stable release on NuGet, and the xrmframework CLI includes a one-time migration path for 2.x solutions.
Business logic is organized into services
XrmFramework has an IService architecture for data access and business logic.
Those typed services can be injected into plugin methods, Custom APIs and external code.
That gives the framework a larger architectural surface than only the plugin entry point.
Custom APIs are first-class
The framework supports defining modern Dataverse Custom APIs from C# and deploying the related:
-
customapi, -
customapirequestparameter, customapiresponseproperty
metadata.
For teams using Custom APIs heavily, that is significant.
Remote debugging is a differentiator
XrmFramework includes a remote debugger that forwards a real Dataverse plugin execution to the developer's machine over Azure Relay.
You can set a Visual Studio breakpoint and step through the execution locally.
Pillaro does not have an equivalent feature.
The tooling surface is broad
The current project also includes:
-
xrmframeworkCLI scaffolding for solutions and projects, - deployment utilities,
- Roslyn source generators, analyzers and code fixes,
- TypeScript tooling,
- web-resource deployment,
- unit-test helpers,
- tracing utilities.
XrmFramework has also been around for years and its NuGet packages have accumulated hundreds of thousands of downloads.
This is a mature, broad toolchain.
Pillaro's design center: make the execution model explicit
Pillaro started from a narrower set of problems.
The recurring issues we wanted to remove were:
- plugin classes where validation and execution gradually became mixed,
- registration that drifted between environments,
- duplicate or stale plugin steps,
- tests that did not verify the real deployed behavior,
- and solutions where every plugin ended up with a slightly different internal structure.
The framework therefore makes the execution unit a Task.
A task has an explicit lifecycle
The simplified model is:
Plugin
↓
Task
├─ Validation
└─ Execution
A task declares its validations separately from its business logic:
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 framework is deliberately opinionated here.
The split between validation and execution is not a convention that every team member has to remember. It is part of the model.
Runtime task registration and deployment registration are separate
The plugin decides which tasks participate in runtime execution (in these samples, Task is the Dataverse activity table, not the framework concept):
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);
}
The explicit step ID gives registration a stable identity across deployments.
Deployment is treated as synchronization
Pillaro's deployment tooling reads registration metadata from code and synchronizes the assembly, steps, images, filtering attributes, rank, configuration and solution membership.
The desired direction is:
Registration in code
↓
Compare with Dataverse
↓
Synchronize state
That is intentionally different from a deployment model where code only adds what is missing.
Testing targets real Dataverse
Pillaro's test package is built around integration tests against an actual Dataverse environment with deployed plugins.
A test can:
- create tracked test data,
- trigger the real operation,
- let Dataverse execute the deployed plugin,
- verify the outcome,
- clean up test data.
That gives a different testing emphasis than a unit-test helper package.
Diagnostics are part of the runtime model
The framework includes execution-flow logging, task-level diagnostics, timings and depth information.
The design preference is to make production behavior inspectable without making live debugging the primary development path.
Pillaro does not provide XrmFramework-style remote debugging.
The comparison
Here is the current high-level picture.
| Area | XrmFramework | Pillaro |
|---|---|---|
| Main design center | Broad Dataverse developer productivity | Explicit plugin/task lifecycle and repeatable delivery |
| Execution unit | Plugin step routed to a method | Plugin orchestrates one or more Tasks |
| Validation/execution split | Team convention | Explicit framework lifecycle |
| Step declaration |
AddStep(...) + method attributes |
Register(IPluginRegistration) fluent API |
| Stable explicit step ID | Not the central public API model | Required by registration API |
| Typed metadata |
.table / .model source files + Roslyn generation + XrmFramework tooling |
Early-bound helper tooling around pac modelbuilder
|
| Service architecture | Typed IService classes and injection |
Task/context model + framework services/features |
| Custom API tooling | Custom API, parameters and response properties deployed from C# | Main-operation tasks; the Custom API definition stays in the solution |
| Build-time diagnostics | Roslyn analyzers and fixes | No equivalent analyzer suite today |
| Live remote debugging | Yes, over Azure Relay | No |
| Runtime diagnostics | Rich tracing | Structured plugin/task diagnostics and performance data |
| Unit-test helpers | Yes | Framework focus is not mocked unit execution |
| Tests against real Dataverse | Build your own approach | Built-in integration testing stack |
| Web-resource tooling | Yes | No |
| Project scaffolding |
xrmframework new ... CLI |
dotnet new + Visual Studio VSIX |
| Plugin deployment | Built-in deployment utilities | Built-in synchronization/deployment tooling |
| Solution pack/unpack | Not the core comparison | Delegated to PAC CLI |
| License | MIT | Apache-2.0 |
| Project maturity | Established, years of usage | Newer framework, first stable generation in 2026 |
There are deliberately no "winner" ticks in this table.
A feature only matters if your team needs it.
The biggest architectural difference
The most important distinction is not remote debugging or model generation.
It is where each framework places the center of gravity.
XrmFramework's center is the broader developer experience:
Typed models
Services
Plugin methods
Custom APIs
Analyzers
Deployment
Remote debugging
Web resources
Pillaro's center is the execution and delivery model:
Plugin
↓
Task
├─ explicit validation
└─ explicit execution
↓
registration as desired state
↓
deployment synchronization
↓
real-environment tests
That difference affects how teams structure their code.
Typed metadata: two valid approaches
Both frameworks try to reduce raw logical-name strings, but the tooling is different.
XrmFramework
In XrmFramework 3.1+, .table files are the source of truth for table metadata. A Roslyn source generator turns them into typed *Definition classes and option-set enums at compile time.
The same model extends to binding models: .model files describe the typed shape and the generator emits the corresponding class and entity-mapping code.
The files can be created or refreshed from Dataverse through XrmFramework tooling such as the xrmframework CLI, while the generated C# does not need to be checked into source control.
This is a framework-owned typed metadata experience with a source-generation model.
Pillaro
Pillaro currently builds its typed entity workflow around Microsoft's Power Platform CLI.
The plugin package generates helper files under Tools/EarlyBound/, but the underlying generator is:
pac modelbuilder build
That is a deliberate design choice.
Pillaro provides the project convention and wrapper; Microsoft owns the actual model generator.
Neither approach is inherently superior.
One provides a more integrated framework experience.
The other keeps the metadata generation boundary closer to first-party tooling.
Debugging vs observability
This is one of the clearest differences.
XrmFramework: debug the live execution
Its remote debugger is compelling when the team wants to:
- reproduce a difficult runtime path,
- attach a breakpoint,
- inspect local state step by step,
- debug against a real environment.
Nothing in Pillaro currently replaces that.
Pillaro: make executions inspectable
Pillaro takes a different direction:
- structured execution flow,
- task-level logging,
- performance timing,
- depth tracking,
- repeatable real-environment tests.
The aim is to reduce the number of cases where a developer needs an attached debugger at all.
Those are different engineering preferences.
Some teams will want both ideas.
Testing: simulated isolation vs deployed behavior
Testing is another place where the word "testing" can hide very different things.
XrmFramework publishes XrmFramework.Tests, described in its package list as unit-test helpers for plugins and services.
That is useful when you want fast isolated feedback around framework code.
Pillaro's built-in testing stack intentionally does something else.
It requires a Dataverse environment with the plugin already deployed.
The test then creates or modifies actual Dataverse records and verifies the resulting behavior.
That makes the tests slower and dependent on an environment.
It also means they verify things a mocked test cannot fully verify:
- actual registration,
- actual pipeline execution,
- platform behavior,
- interactions between deployed plugins,
- real Dataverse data operations.
A mature project may want both unit-level and integration-level coverage.
The frameworks simply emphasize different layers.
Breadth has a cost — and narrowness has a cost
XrmFramework's breadth is a benefit when you want one coherent stack.
It also means there is more framework to adopt:
- model definitions,
- service architecture,
- deployment utilities,
- analyzers,
- debugger,
- Custom API conventions,
- potentially web-resource tooling.
If your team wants those things, the integration is valuable.
If your problem is only plugin structure and deterministic registration, it may be more surface than you need.
Pillaro has the opposite trade-off.
It does not currently provide:
- a remote debugger,
- XrmFramework's analyzer suite,
- TypeScript/web-resource tooling,
- Custom API definitions deployed from code (Pillaro runs the main-operation task, but the
customapirecords and their parameters stay in your solution), - the same years of ecosystem maturity.
If your team needs those features, that matters.
A smaller surface is only an advantage when the smaller surface contains the things you actually need.
When XrmFramework is a natural fit
XrmFramework deserves serious consideration when your team wants a broad Dataverse development platform and values several of these together:
- framework-owned typed model tooling,
- a service-oriented architecture across plugins and external code,
- full Custom API tooling,
- Roslyn diagnostics,
- remote debugging,
- web-resource deployment,
- a mature package ecosystem,
- years of production usage.
It is especially interesting when the goal is:
remove as much recurring Dataverse development friction as possible through one integrated framework.
When Pillaro is a natural fit
Pillaro is aimed more directly at teams that care about:
- explicit task-sized units of business logic,
- enforced validation → execution structure,
- stable registration identity,
- registration synchronized from code,
- avoiding duplicate/stale plugin steps,
- structured diagnostics,
- integration tests against real Dataverse,
- using Microsoft tooling such as
pac modelbuilderwhere it already solves the problem.
The design goal is closer to:
keep the framework surface focused, but make the plugin lifecycle and delivery model highly explicit.
Migration cost matters more than feature tables
If you already have a large XrmFramework solution, this article is not an argument to migrate it.
A framework replacement changes more than NuGet packages.
It can affect:
- architecture,
- project structure,
- registration,
- tests,
- deployment,
- developer habits,
- operational tooling.
A migration only makes sense when the destination solves a real problem that justifies that cost.
The same is true in the opposite direction.
If a Pillaro project needs capabilities that are central to XrmFramework, the feature gap should be evaluated honestly instead of forcing a smaller framework to become something it was not designed to be.
My conclusion
I do not think the useful conclusion is:
XrmFramework is for large projects and Pillaro is for small projects.
That is too simplistic.
A better distinction is:
XrmFramework optimizes for breadth of developer productivity.
Pillaro optimizes for explicitness of plugin architecture, deployment state and deployed-behavior verification.
Those priorities can exist in projects of very different sizes.
The right choice depends on which source of friction your team actually wants the framework to own.
What comes next
The final article in this series zooms out.
Instead of comparing frameworks, Part 4 maps the Dataverse plugin tooling stack in 2026:
- what belongs to the SDK,
- what PAC CLI now owns,
- where PRT still fits,
- what frameworks add,
- and where older deployment tools such as spkl fit in a modern codebase.
Sources
- XrmFramework repository and documentation
- XrmFramework NuGet packages
- Pillaro Dataverse Plugin Framework
- Microsoft Learn: Community Tools for Microsoft Dataverse — Pillaro
- Microsoft Marketplace: Pillaro Dataverse Plugin Framework
- Pillaro Getting Started
- Pillaro Deployment Plugins
- Pillaro Testing Overview
- Microsoft: pac modelbuilder
Disclosure: I maintain Pillaro. XrmFramework descriptions in this article are based on its current public repository and documentation as reviewed in October 2026. Corrections are welcome.
Top comments (0)