Dataverse plugin development no longer has one toolchain. The SDK, PAC CLI, Plug-in Registration Tool, Visual Studio tooling, native Git integration and plugin frameworks solve different layers of the problem. The important question is no longer "Which tool should I use?" but "Which tool should own which responsibility?"
A few years ago, a Dataverse project could easily grow around one utility.
The same tool might:
- generate early-bound classes,
- deploy the assembly,
- register plugin steps,
- deploy web resources,
- export and import solutions,
- pack and unpack solutions.
That made sense when first-party tooling covered less of the lifecycle.
In 2026, the picture is different.
Microsoft's Power Platform CLI now owns a much larger part of the developer and ALM surface. Power Platform Tools for Visual Studio can create, deploy, register, profile and debug plugins. The Plug-in Registration Tool still has a clear role. Dataverse now has native Git integration and a source-control-oriented YAML representation for solutions. Frameworks sit above that stack and add architecture, conventions and repeatability.
The result is not one "best tool".
It is a stack of responsibilities.
My rule for a modern Dataverse project is simple:
Use first-party tooling where the platform already has a good owner. Add a framework where you need architecture, consistency or stronger delivery guarantees.
Start with the platform: the Dataverse plugin SDK
Everything still starts with the Dataverse event framework.
A C# plugin executes because:
- a Dataverse operation raises an event,
- a plugin assembly or package is registered,
- a step connects a plugin type to a message, table and pipeline stage,
- Dataverse executes the code inside its plugin runtime.
At code level, the standard primitives are still familiar:
IPlugin
IPluginExecutionContext
IOrganizationService
ITracingService
Entity
EntityReference
A framework does not replace that contract.
It sits above it.
That matters because every abstraction eventually maps back to platform concepts such as:
- message,
- table,
- pipeline stage,
- synchronous or asynchronous execution,
- filtering attributes,
- pre/post images,
- execution order,
- configuration,
- user context,
- transaction behavior.
If an abstraction makes those concepts impossible to see, it has probably hidden too much.
Microsoft now owns much more of the tooling layer
The biggest change compared with older Dynamics development stacks is how much Power Platform CLI now covers.
It is no longer just an authentication helper.
Plugin projects: pac plugin
A new plugin class library can be initialized with:
pac plugin init
and an assembly or plugin package can be pushed with:
pac plugin push
For a Plain SDK project, that gives you a supported first-party path for project creation and deployment of the plugin binary/package.
What it does not solve by itself is the architecture inside the plugin or the full desired-state definition of every step.
That distinction is important.
Registration tooling: PRT still has a job
The Plug-in Registration Tool is still part of the supported Dataverse development workflow and can be launched through PAC CLI:
pac tool prt
(pac tool commands are available only in the .NET Framework build of PAC CLI, so in practice on Windows.)
PRT remains useful for:
- registering and inspecting assemblies,
- creating or editing steps,
- inspecting images and filtering attributes,
- troubleshooting existing environments,
- profiling and replaying plugin executions,
- understanding legacy solutions.
Power Platform Tools for Visual Studio can also register and manage plugin packages and provides an integrated profiling/debugging workflow.
So manual tooling is not obsolete.
The real question is whether manual state is your source of truth.
There is a big difference between:
"I use PRT to inspect and diagnose the environment."
and:
"Production is correct because somebody remembered which boxes to click."
The first is a useful tool.
The second is operational risk.
Typed code generation: pac modelbuilder
Microsoft's supported typed-code generator is:
pac modelbuilder build
Microsoft documents it as the replacement for CrmSvcUtil.exe distributed through the older Microsoft.CrmSdk.CoreTools package.
This is a good example of a responsibility that many frameworks no longer need to fully reimplement.
A framework can still add value through:
- project conventions,
- configuration,
- wrappers,
- generated helper files,
- filtering rules,
- onboarding.
But the underlying code-generation engine can remain first-party.
That is the approach Pillaro takes today.
Solution lifecycle: pac solution
The pac solution command group covers a large part of the solution lifecycle, including operations such as:
- initialization,
- cloning,
- synchronization,
- export/import,
- pack/unpack,
- checks,
- versioning,
- upgrades.
Microsoft explicitly states that standalone SolutionPackager is no longer the recommended way to pack and unpack solutions because that capability is incorporated into PAC CLI.
For a plugin framework, that changes the scope discussion.
A framework should have a strong reason before it starts owning generic solution packaging in 2026.
Native Git integration changes the ALM picture again
This is one of the biggest changes to the 2026 tooling stack.
Dataverse now has native Git integration for solution source control.
That means a development environment or solution can be connected directly to a supported Git provider, and makers can commit and synchronize Dataverse solution changes with source control from the Power Platform experience.
At the time of writing:
- the integration is generally available for Azure DevOps (since April 2025) and requires Managed Environments,
- GitHub support is in public preview (since August 2026),
- Microsoft recommends using the integration in development environments and using builds/pipelines to deploy downstream.
The source-control representation is also changing.
Dataverse Git integration uses a YAML-based source format, and pac solution clone can produce the same format for code-first workflows.
That matters because the ALM stack is moving further toward:
Development environment
↕
Git source of truth
↓
Build
↓
Solution artifact
↓
Test / Production
instead of:
Development environment
↓
Export ZIP
↓
Hope the repository reflects reality
This does not remove the need for plugin source code, build pipelines or deployment conventions.
It does make source control a much more first-class part of the platform.
Visual Studio is another valid first-party path
Power Platform Tools for Visual Studio supports a substantial part of the plugin lifecycle.
It can help with:
- plugin project creation,
- package creation,
- uploading and registering packages,
- registration management,
- profiling,
- replay debugging.
This matters because "Plain SDK" no longer means:
write a DLL and manually do everything else.
There is now a meaningful first-party developer experience around the SDK.
A framework therefore has to add value above that baseline.
The stack by responsibility
This is how I currently separate the layers.
| Responsibility | First-party / platform layer | Optional higher-level layer |
|---|---|---|
| Plugin execution contract | Dataverse SDK | Framework execution model |
| Create plugin project |
pac plugin init, Visual Studio tools |
Framework templates/scaffolding |
| Build/package plugin | .NET + plugin package tooling | Framework build conventions |
| Push plugin binary/package |
pac plugin push, Visual Studio tools |
Framework deployer |
| Register/inspect steps | PRT, Visual Studio tools | Framework registration model |
| Define registration as code | Team automation | Plugin framework |
| Generate typed entities | pac modelbuilder |
Framework wrapper/convention |
| Pack/unpack solutions | pac solution |
Usually no framework needed |
| Source-control solution metadata | Dataverse Git integration / pac solution clone
|
Team ALM conventions |
| Environment authentication | pac auth |
CI/CD secret conventions |
| Runtime architecture | Your code | Plugin framework |
| Validation structure | Your code | Plugin framework |
| Diagnostics | Dataverse tracing/profiler | Framework diagnostics |
| Testing conventions | Your test stack | Framework test package |
| Registration synchronization | Your CI/tooling | Framework deployer |
| Web-resource delivery | Platform/CI tooling | Some broader frameworks |
| Live remote debugging | Profiler/replay or framework-specific tooling | XrmFramework-style remote debugging |
The important pattern is that the modern stack is composable.
You do not need one dependency to own every row.
Three reasonable project shapes
Most Dataverse plugin projects can be described by one of three approaches.
1. Minimal first-party stack
Dataverse SDK
+
pac plugin
+
PRT / Visual Studio tools
+
pac modelbuilder
+
pac solution
+
Git / Dataverse Git integration
This is a strong choice when:
- the solution has only a few plugins,
- the team understands the Dataverse pipeline well,
- internal conventions are enough,
- third-party dependencies are undesirable,
- registration complexity is limited.
There is nothing second-class about this architecture.
It has the smallest dependency surface.
The trade-off is simple:
your team owns the architecture and conventions.
That includes decisions such as:
- how plugin classes are structured,
- how validation is separated from execution,
- how steps are represented,
- how environments are kept consistent,
- how testing is done.
2. Structured framework stack
Dataverse SDK
↓
Plugin framework
↓
Architecture + registration + diagnostics + testing
plus
PAC CLI / Git / platform ALM tooling
This makes sense when the recurring problem is no longer project creation.
The problem is consistency.
A framework can add:
- repeatable plugin structure,
- explicit execution units,
- registration in code,
- validation conventions,
- diagnostics,
- integration testing,
- deterministic deployment,
- onboarding standards.
The principle I prefer is:
Use the framework where it adds architecture. Keep first-party tooling where the platform already has a strong owner.
For example, Pillaro provides project-local helpers for early-bound generation, but the actual generator remains pac modelbuilder.
For solution lifecycle, PAC CLI remains the intended layer.
That keeps the boundaries clearer.
3. Existing / legacy tooling stack
Many mature solutions still look more like this:
Dataverse SDK
+
spkl
+
older SDK tooling
+
custom scripts
That is not automatically wrong.
If the project is stable, the deployment process is understood and the toolchain still works, migration may create more risk than value.
But for an actively developed solution, I would periodically ask:
- Are the Microsoft dependencies current?
- Does authentication still match modern tenant requirements?
- Is the deployment tool still a good long-term dependency?
- Are solution operations now better owned by PAC CLI?
- Is typed-code generation better handled by
pac modelbuilder? - Is plugin registration reproducible?
- Is the tool still present because it adds unique value, or because it historically owned five responsibilities at once?
That was the reason for the first article in this series: moving from spkl is not mainly about replacing one executable with another.
It is about deciding who should own each responsibility now.
Frameworks belong above the generic tooling layer
I find it useful to draw the architecture like this:
┌─────────────────────────────────────────────┐
│ Business logic / plugin architecture │
│ Tasks, services, validation, conventions │
│ FRAMEWORK │
├─────────────────────────────────────────────┤
│ Registration / deployment invariants │
│ Framework deployer or team automation │
├─────────────────────────────────────────────┤
│ Source control / ALM │
│ Git integration / pipelines / pac solution │
├─────────────────────────────────────────────┤
│ Microsoft developer tooling │
│ pac plugin / modelbuilder / PRT / VS tools │
├─────────────────────────────────────────────┤
│ Dataverse SDK + event framework │
└─────────────────────────────────────────────┘
This makes framework scope easier to reason about.
A framework is strongest when it owns the layers where team consistency, architecture and delivery invariants matter.
It becomes harder to justify when it simply recreates generic platform tooling that Microsoft already maintains.
Where XrmFramework fits
As discussed in Part 3, XrmFramework deliberately owns a broad part of the upper stack.
Its current development model includes areas such as:
- declarative plugin registration,
- typed metadata/model tooling,
- service architecture,
- Custom API tooling,
- deployment utilities,
- Roslyn generation/analyzers,
- scaffolding,
- web-resource tooling,
- remote debugging.
That is a coherent strategy:
make Dataverse development feel like a more integrated .NET development platform.
For teams that want that breadth, the framework can become the center of the developer experience.
Where Pillaro fits
Pillaro intentionally owns a narrower set of upper-layer responsibilities.
Its current center is:
- task-based execution,
- explicit validation and execution phases,
- registration metadata in code,
- stable step identity,
- deployment synchronization,
- structured diagnostics,
- runtime configuration,
- integration testing against real Dataverse.
For early-bound generation, Pillaro uses project-local helper tooling around Microsoft's:
pac modelbuilder build
For the general solution lifecycle, PAC CLI remains the intended owner.
For repository and environment ALM, standard Git and Power Platform tooling remain outside the framework.
The strategy is:
own the plugin architecture and delivery invariants; reuse Microsoft tooling for generic platform lifecycle operations.
Pillaro is listed in Microsoft Learn's Community Tools for Microsoft Dataverse catalog and is distributed through Microsoft Marketplace for the Dataverse-side runtime, while the C# framework is consumed through NuGet.
That improves discovery and deployment, but it does not change the support model: Pillaro remains a community-maintained framework.
Where PRT still fits
There is a temptation to call GUI tools obsolete once CI/CD exists.
I do not think that is accurate.
PRT is still useful when you need to:
- inspect what is really deployed,
- diagnose a registration,
- profile a plugin,
- test an idea in a development environment,
- understand a legacy solution,
- compare expected and actual state.
The problem is not the GUI.
The problem is undocumented state.
A healthy setup can use PRT every week and still have fully reproducible deployments.
Where AI-assisted development changes the equation
AI makes code generation cheaper.
It does not make architecture less important.
In practice, coding agents work better when a repository has:
- predictable project structure,
- explicit registration,
- small units of behavior,
- clear validation rules,
- reusable tests,
- deterministic deployment,
- useful diagnostics.
The same is true for human developers.
As code becomes easier to generate, the value shifts away from:
"Who can type the C# fastest?"
toward:
"Is the intended behavior explicit enough to implement, verify, review and operate repeatedly?"
That is an architecture and delivery problem.
It is one reason I expect frameworks and internal engineering standards to remain relevant.
My default approach for a new Dataverse plugin project in 2026
I would make the decisions in this order.
1. First ask whether you need a plugin
Microsoft still recommends considering declarative business-logic options first.
Use custom C# because the requirement needs transactional code, platform event handling, performance, complex integration logic or another capability that declarative options cannot reasonably provide.
Not because "we always use plugins."
2. Start with current Microsoft tooling
For the responsibilities Microsoft already owns well, use the platform tools:
pac plugin
pac modelbuilder
pac solution
pac tool prt
Power Platform Tools for Visual Studio
For solution source control, evaluate native Dataverse Git integration and the current YAML source format.
Avoid adding a second owner for the same responsibility without a clear reason.
3. Decide how plugin architecture will be standardized
Choose explicitly between:
- Plain SDK + team conventions,
- an internal standard/framework,
- a public framework.
Do not let the architecture emerge accidentally plugin by plugin.
4. Put registration state under control
A build artifact is not enough.
You also need to know:
- which step runs,
- on which message,
- on which table,
- in which stage,
- synchronously or asynchronously,
- which attributes trigger it,
- which images exist,
- under which user context,
- in what order it executes.
That state should be reviewable and reproducible.
5. Put solution state under source control
Plugin source code and Dataverse solution metadata solve different problems.
Both matter.
In 2026 there are stronger first-party options than before:
- Dataverse Git integration,
- YAML-based solution source representation,
-
pac solution clone, - standard CI/CD pipelines.
The exact workflow can differ between teams.
The important part is that source control—not someone's development environment—becomes the durable source of truth.
6. Decide what "tested" means
There is a large difference between:
- unit-testing a service,
- simulating a plugin context,
- integration-testing against Dataverse,
- replay-debugging a captured execution,
- end-to-end verification after deployment.
Use the level that matches the risk.
But decide deliberately.
7. Keep the stack replaceable
Every additional tool should have a clear boundary.
If the framework owns plugin architecture, let it own plugin architecture.
If PAC CLI owns generic solution packaging, let PAC CLI own it.
If Git owns source history, do not hide the only source of truth inside an environment.
Clear boundaries make future migrations much easier.
The series in one picture
The four articles in this series map to four different decisions:
Part 1
Existing spkl project
↓
What should replace the responsibilities it owns?
Part 2
Plain SDK project
↓
When does framework abstraction pay off?
Part 3
Framework decision
↓
Pillaro or XrmFramework-style approach?
Part 4
Whole developer stack
↓
Which tool should own which responsibility?
That is the main point of the series.
There is no single correct Dataverse plugin stack.
There should, however, be a clear reason for every layer you add.
Closing thought
A mature development stack is not the stack with the most tooling.
It is the stack where ownership is obvious.
When something breaks, you should be able to ask:
- Is this a Dataverse runtime problem?
- An SDK problem?
- A registration problem?
- A PAC CLI / ALM problem?
- A framework problem?
- A business-logic problem?
- A pipeline problem?
And know where to look.
That clarity is more valuable than any individual feature.
Sources
- Microsoft: Use plug-ins to extend business processes
- Microsoft: Apply business logic using code
- Microsoft: Register a plug-in
- Microsoft: Power Platform developer tools
- Microsoft: Power Platform Tools for Visual Studio
- Microsoft: pac plugin
- Microsoft: pac tool
- Microsoft: pac modelbuilder
- Microsoft: pac solution
- Microsoft: SolutionPackager guidance
- Microsoft: Debug a plug-in (Plug-in Profiler and replay)
- Microsoft: Dataverse Git integration
- Microsoft: Connect Dataverse Git integration to GitHub (preview)
- Microsoft: Solution YAML source control format
- XrmFramework
- Pillaro Dataverse Plugin Framework
- Microsoft Learn: Community Tools for Microsoft Dataverse — Pillaro
- Microsoft Marketplace: Pillaro Dataverse Plugin Framework
Disclosure: I maintain Pillaro. This article is a tooling map, not a recommendation that every Dataverse project should use Pillaro or any other framework. Tooling status reviewed in October 2026.
Top comments (0)