HomeBlogCustomization & DevelopmentMicrosoft Partner · Charlottesville, VA
Customization & Development

How to Register a Plugin in Dynamics 365: Step-by-Step

Register a plugin in Dynamics 365 with the Plugin Registration Tool. Microsoft's Dataverse sandbox allows 2-minute execution windows. Learn the full process.

Dynamics 365 GroupApril 30, 202519 min read← All posts
How to Register a Plugin in Dynamics 365: Step-by-Step

TL;DR: To register a plugin in Dynamics 365, compile your .NET assembly, open the Plugin Registration Tool (PRT), connect to your Dataverse environment, register the assembly as a database-deployed DLL, add a step specifying the target entity and message (for example, Create on Account), select the execution pipeline stage, and optionally attach pre-event or post-event images. The plugin then runs server-side each time the configured event fires, within Microsoft’s 2-minute sandbox timeout.

A plugin is custom .NET code that extends Dynamics 365 by running server-side logic when data changes. Unlike client-side scripts or cloud flows, plugins execute inside the Dataverse database transaction, so your business rules run regardless of how the data change originates. In my experience implementing Dynamics 365 for clients across manufacturing and professional services, plugins handle the logic that no other tool can enforce reliably — validation rules, mandatory field defaults, cross-entity consistency checks. This guide covers the full registration process, from installing the tools through debugging deployed code.

What Is a Plugin in Dynamics 365?

A plugin is a custom .NET assembly that executes server-side within Microsoft Dataverse — the data layer underlying Dynamics 365 — in response to data events such as Create, Update, Delete, or Assign. When an event fires, Dataverse passes it through an execution pipeline, and your plugin intercepts it at a stage you specify. Microsoft documents the complete plug-in model in its Dataverse developer reference.

At the code level, every plugin implements a single interface: IPlugin and its Execute(IServiceProvider) method. When the registered event fires, the platform instantiates your class and hands it a service provider containing the execution context, tracing service, and organization service. Plugins differ from other customization tools in one critical way: they run inside the platform’s execution pipeline, not outside it. A business rule or a Power Automate flow can be bypassed if data changes arrive through an unexpected channel. A plugin cannot. Whether the record is created through the web client, a mobile app, an API call, or an import job, the plugin fires. This guarantee is why plugins remain the primary mechanism for enforcing critical business logic in Dynamics 365.

The Event Execution Pipeline

Every data operation in Dataverse passes through a pipeline with three stages where custom code can run. Microsoft defines these stages numerically, and the stage you choose determines what your plugin can see, modify, and cancel.

  • PreValidation (Stage 10): Executes before the main system operation and before security checks. Validation logic belongs here, especially validation that should run regardless of the caller’s permissions.
  • PreOperation (Stage 20): Executes after security checks but before the database write. Your plugin can read and modify the entity’s attributes in the Target parameter before they are committed.
  • PostOperation (Stage 40): Executes after the main operation completes, still within the database transaction. Use this stage to update related records, trigger integrations, or perform post-save processing.

PreValidation can cancel an operation before the user hits a permission error. PreOperation can change field values before they are saved. PostOperation can act on the final committed data. Selecting the wrong stage is a common source of plugin bugs — if your code modifies Target attributes but the step is registered in PostOperation, the changes never take effect because the database write has already occurred.

Synchronous vs. Asynchronous Execution

When registering a step, you choose between synchronous and asynchronous execution mode. The choice affects user experience, error handling, and transaction behavior.

Synchronous plugins run inline with the user’s operation. The interface waits for the plugin to complete before the save returns to the user. The logic is immediate and visible, but a slow plugin degrades the user experience. Synchronous plugins must finish within the sandbox’s 2-minute execution limit or the platform terminates them and rolls back the transaction, as documented in Microsoft’s plug-in isolation guidance.

Asynchronous plugins are queued and executed by the Asynchronous Service after the main operation completes. The user’s save returns immediately. Asynchronous execution suits tasks that do not need to block the user: sending email notifications, generating documents, or syncing data to external systems. If an asynchronous plugin fails, the platform can retry it automatically.

A practical guideline: if the logic must block the save (validation, mandatory field defaults, transactional consistency), use synchronous. If the logic is a side effect (notifications, logging, integration sync), use asynchronous. Mixing both — a synchronous pre-validation plugin paired with an asynchronous post-operation plugin — is a common pattern for complex scenarios.

Prerequisites for Plugin Registration

Before registering a plugin, you need a configured development environment and either the System Administrator or System Customizer security role in your target Dataverse environment. These requirements follow Microsoft’s plug-in development tutorial.

Development Tools

Plugin development needs four components: Visual Studio, the .NET Framework runtime, the Dataverse SDK packages, and the Power Platform CLI. Install the following on your development machine:

  • Visual Studio 2019 or later with the .NET desktop development workload. The free Community edition is sufficient for plugin development.
  • .NET Framework 4.6.2 or later. Dataverse plugins target the .NET Framework specifically — not .NET Core, .NET 5, or later versions. Microsoft documents this version requirement in its Power Platform developer tools guide. Targeting the wrong framework version is the most common build error developers encounter.
  • NuGet packages. Add Microsoft.CrmSdk.CoreAssemblies to your project for access to the core SDK types: IPlugin, IPluginExecutionContext, IOrganizationService, and ITracingService. This package provides the interfaces your plugin implements and the services it receives through the IServiceProvider parameter.
  • Power Platform CLI. Install it to download and launch the Plugin Registration Tool without manual NuGet extraction.

Required Permissions

Your Dataverse user account needs one of these security roles to register plugins:

  • System Administrator — full control over all system customization and configuration.
  • System Customizer — can create and register plugins with limited data access scope.

Without one of these roles, the Plugin Registration Tool cannot connect to the environment or upload assemblies. In managed environments, a Power Platform administrator may also need to approve plugin deployment policies before assemblies can be registered.

Installing the Plugin Registration Tool

The Plugin Registration Tool (PRT) is distributed through the Power Platform CLI, which is Microsoft’s recommended installation method. Install the CLI as a global .NET tool:

dotnet tool install --global Microsoft.PowerApps.CLI

Once installed, launch the Plugin Registration Tool from the command line:

pac tool prt

This opens the PRT as a standalone Windows application. The CLI keeps the tool current — running pac tool prt always launches the latest version without manual download. If your organization must retain a specific older version, validate its compatibility against Microsoft’s current Plug-in Registration Tool guidance or build from source using the PowerApps-Samples repository on GitHub.

Registering a Plugin: Step by Step

Registration involves five steps: connect to your environment, upload the compiled assembly, configure a step that defines the trigger, select the pipeline stage, and optionally register images. The following sections cover each step in detail.

Step 1: Connect to Your Dataverse Environment

Open the Plugin Registration Tool and click Create New Connection. Provide the connection details:

  • Deployment Type: Online (for Dynamics 365 cloud environments)
  • Authentication Type: OAuth
  • Discovery Server: Your region endpoint (for example, https://org.crm.dynamics.com)
  • User Name and Password: Your Dataverse administrator credentials

Click Connect, select your target environment from the list, and click Login. The tool loads the environment’s current registered assemblies and steps in the left panel.

If sign-in fails, confirm that your account holds the System Administrator or System Customizer role and that your organization’s conditional access policies permit the connection. The PRT supports multi-factor authentication through the OAuth flow.

Step 2: Register the Assembly

Select your environment node in the left panel and click Register New Assembly. Browse to the compiled DLL from your Visual Studio project, typically found in bin/Release after a release build.

Configure three settings:

  • Isolation Mode: Choose Sandbox. This is mandatory for all Dynamics 365 online environments. Sandbox isolation restricts the plugin’s runtime permissions to prevent unauthorized system access, as documented in Microsoft’s plug-in isolation guidance.
  • Source Type: Choose Database. This stores the assembly inside Dataverse, deploying it automatically to all servers and including it in solution exports so it moves cleanly between dev, test, and production. The alternatives — Disk and GAC — apply only to on-premises deployments and are not available for online environments.
  • Assembly Location: The file path to your compiled DLL.

Click Register Selected Plugins. The tool uploads the assembly and lists each public class implementing IPlugin as a selectable node in the tree view. At this point the assembly is deployed but inactive — no code runs until you register a step.

Step 3: Register a Step

A step defines the trigger condition: when and on what entity your plugin runs. Right-click the plugin class node and select Register New Step.

Configure these fields:

  • Message: The operation that triggers execution. Common messages include Create, Update, Delete, SetState, and Assign. Microsoft maintains a full event reference listing supported messages and the entities that accept them.
  • Primary Entity: The target table, for example account, contact, or opportunity.
  • Filtering Attributes: For Update messages, select only the attributes whose changes should fire the plugin. Leaving this blank causes the plugin to run on every field change, consuming server resources unnecessarily. A plugin that validates credit limit changes should filter on creditlimit alone, not fire when someone updates a phone number.
  • Event Pipeline Stage: Choose PreValidation (10), PreOperation (20), or PostOperation (40).
  • Execution Mode: Synchronous or Asynchronous.
  • Execution Order: Controls sequencing when multiple plugins share the same message and entity. Lower values run first. The default is 1.

Click Register New Step. The step appears beneath the plugin class in the tree view, marked with a green checkmark indicating it is active.

Step 4: Choose the Pipeline Stage

The pipeline stage determines what data your plugin can access and whether it can modify or cancel the operation:

Stage Can modify entity? Can cancel operation? Transaction active?
PreValidation (10) No Yes No
PreOperation (20) Yes, via Target Yes Yes
PostOperation (40) No (read-only) Yes (rolls back) Yes

Register in PreOperation when your plugin needs to set or modify field values before they are saved. Register in PreValidation when your plugin performs permission-independent validation — for example, checking whether an opportunity has a required related record before allowing deletion. Register in PostOperation when your plugin needs to act on the final committed data, update related records, or trigger downstream processing.

A frequent mistake: registering a data-modification plugin in PostOperation. By Stage 40 the main database write is complete, so changes to Target are ignored. Always use PreOperation for attribute modifications.

Step 5: Register Images (Optional)

Images capture entity attribute snapshots at specific pipeline points. They are essential when your plugin needs to compare before and after values during an Update operation.

Right-click the step and select Register New Image:

  • Image Type: Pre-Image captures the entity before the operation; Post-Image captures it after. For Update messages, register both if your logic needs the delta between old and new values.
  • Parameters: Select only the attributes your plugin uses. Requesting all attributes wastes memory and adds overhead to every execution.
  • Entity Alias: The key your code uses to retrieve the image, accessed in C# as context.PreEntityImages["alias"] or context.PostEntityImages["alias"].

Without a registered image, the Target in an Update message contains only the fields being changed. The previous values are inaccessible. If your plugin needs to know what a field was before the update — for example, to detect that a status changed from Draft to Approved — a Pre-Image is required.

Testing and Debugging Registered Plugins

After registration, test the plugin by performing the triggering action in Dynamics 365. For a plugin registered on Create of account, create a new account record and verify the expected behavior. If the plugin modifies fields, confirm the changes appear on the saved record. If it throws an exception, verify the error message reaches the end user.

Tracing and the Plug-in Trace Log

Add tracing to your plugin using ITracingService. Tracing output writes to the Plug-in Trace Log entity in Dataverse, which persists detailed execution information including timestamps, input parameters, and exception details.

public void Execute(IServiceProvider serviceProvider)
{
    var tracingService = (ITracingService)
        serviceProvider.GetService(typeof(ITracingService));
    var context = (IPluginExecutionContext)
        serviceProvider.GetService(typeof(IPluginExecutionContext));

    tracingService.Trace("Plugin started. Entity: {0}, Message: {1}",
        context.PrimaryEntityName, context.MessageName);

    // Business logic here

    tracingService.Trace("Plugin completed successfully.");
}

Enable trace logging under Settings > System Settings > Customization tab, setting Enable logging for plug-ins to All or Exception. Microsoft documents the trace log configuration in its developer guidance. Trace logs are not available in production environments unless an administrator enables them, and they consume storage — review and purge old logs periodically.

The Plugin Profiler

For line-by-line debugging, use the PRT’s Profiler feature. The profiler captures a snapshot of the execution context, including all input parameters, pre-images, and post-images, and lets you replay the execution locally in Visual Studio.

To use it:

  1. In the PRT, select your plugin step and click Start Profiling.
  2. Trigger the plugin by performing the action in Dynamics 365.
  3. Return to the PRT and click Save Profile — this downloads the captured execution context.
  4. Open your Visual Studio project, set breakpoints in Execute, and use Attach to Process with the Plugin Registration Tool selected.

Microsoft describes the full debugging workflow in its developer tutorials. The profiler is the most effective way to diagnose logic errors that only reproduce with specific data conditions.

Best Practices for Plugin Registration

These patterns prevent the performance and reliability problems I encounter most often in production Dynamics 365 environments. Each recommendation addresses a specific failure mode I have diagnosed in client deployments, and following them from the first registration avoids costly remediation later.

Keep plugins stateless. Dataverse may instantiate your plugin class multiple times and reuse instances across unrelated requests. Never store request-specific data in class-level fields. All state belongs in local variables within Execute. The platform does not guarantee a fresh instance per call, and cached data from a previous request can corrupt the current one silently.

Use filtering attributes on Update steps. If your plugin responds only to changes in the creditlimit field, register that single attribute as a filter. Without filters, every unrelated field update triggers your plugin and wastes server cycles. On high-volume entities, unfiltered Update plugins are a leading cause of performance complaints.

Respect the 2-minute execution limit. The sandbox terminates any plugin exceeding two minutes of execution time, as documented in Microsoft’s isolation guidance. If your logic calls external services with unpredictable latency, move it to an asynchronous plugin or replace it with a Power Automate flow integrated with your ERP. External HTTP calls inside a synchronous plugin are the single most common cause of timeout exceptions.

Guard against infinite loops. A plugin that updates its own entity can trigger itself recursively. Check context.Depth > 1 to detect re-entrant execution and exit early when the plugin was triggered by another plugin rather than a direct user action. Without this guard, a self-triggering plugin can exhaust the platform’s depth limit and throw a sandbox exception.

Version your assemblies. Increment the assembly version in Visual Studio project properties before each update. When you re-register, the PRT matches the new version to the existing registration. Mismatched versions cause deployment conflicts that require unregistering and re-registering the assembly, losing all configured steps.

Common Issues and Troubleshooting

Most registration problems stem from three causes: incorrect .NET targeting, misconfigured steps, or sandbox security restrictions. Each has a straightforward fix.

“Assembly cannot be loaded” error. The DLL likely targets the wrong .NET Framework version. Verify the project targets .NET Framework 4.6.2 or later and rebuild in Release configuration. Also confirm that the assembly is not signed with a strong-name key that conflicts with the existing registration.

Plugin does not execute. Confirm the step shows a green checkmark (active) in the PRT tree view. Verify the message and entity match your test action. For Update steps, check that the filtering attributes include the field you changed. A step filtered on creditlimit will not fire when you update telephone1.

Sandbox exception on external calls. The sandbox restricts certain system-level operations including file system access, registry access, and network sockets other than HttpClient and WebSocket. If your plugin needs to interact with external services, use webhooks registered through the PRT or route the call through an Azure Service Bus integration for platform-supported connectivity. Microsoft describes the full sandbox restrictions in its isolation documentation.

SQL timeout expired. The plugin’s database operations exceeded the platform’s command timeout. Optimize queries using ColumnSet to request only needed columns, reduce the number of records retrieved, or split the work across smaller operations. Avoid RetrieveMultiple calls inside loops — batch your queries instead.

Plugin works in dev but not in production. Check whether the production environment has different security roles, solution layers, or managed properties that restrict custom code. Also verify that any referenced web resources or configuration records exist in the target environment.

Deploying Plugins Across Environments

Once a plugin is registered and tested in a development environment, the standard approach to moving it downstream is to include the assembly and its steps in a Dataverse solution. When you register with Database as the source type (as recommended in Step 2), the assembly and all its steps, images, and configuration are automatically included in solution components.

Key considerations for solution-based deployment:

  • Solution layering. If multiple solutions add steps to the same entity and message, execution order depends on each solution’s layer position. Plan execution order carefully when multiple solutions coexist.
  • Managed properties. When exporting as managed, you can control whether downstream environments can edit or unregister your steps. Set customization allowances based on your governance model.
  • Assembly updates. When you update plugin code, increment the version number, rebuild, and update the assembly through the PRT in the development environment. Export a solution update — the new assembly version deploys with the patch.
  • CI/CD with the CLI. The Power Platform CLI supports exporting and importing solutions programmatically, enabling automated deployment pipelines. Microsoft documents the solution lifecycle in its ALM guidance.

When to Use Plugins vs. Alternatives

Plugins are the right choice when logic must run server-side and transactionally, but several alternatives cover common needs with less complexity and lower maintenance overhead.

Approach Runs server-side? Transactional? Code required? Best for
Plugin Yes Yes Yes (.NET) Critical business logic, data integrity rules
Business rule Partially No No Simple field validation, conditional visibility
Power Automate flow Yes No Minimal Multi-step orchestration, integrations, notifications
Classic workflow Yes No No Record assignments, status changes
Webhook Yes (external) No External Event-driven integration with external systems

Choose a plugin when the logic must run regardless of the client, when you need full access to the Organization Service SDK, or when the operation must participate in the same database transaction as the triggering event. For everything else — notifications, simple validations, cross-system orchestration — Power Automate or business rules are simpler to build and maintain.

A practical decision framework: if a failed execution should roll back the entire save (preventing an invalid record from being created), use a synchronous plugin. If a failed execution should retry later without blocking the user (sending a confirmation email), use an asynchronous plugin or a Power Automate flow.

For projects that require custom plugin development but lack in-house C# expertise, our Dynamics 365 services include plugin design, registration, testing, and ongoing maintenance. If you are evaluating implementation partners, this guide on choosing a Dynamics 365 partner covers what to look for.

FAQ

Can I register plugins without the Plugin Registration Tool?

Yes. The Power Platform CLI supports scripted plugin deployment, and plugins can be packaged in managed solutions for automated distribution across environments. The PRT remains the standard tool for interactive development, testing, and debugging, but CI/CD pipelines typically use the CLI or solution import for production deployments.

What .NET version do Dynamics 365 plugins require?

Plugins target .NET Framework 4.6.2 or later. They do not run on .NET Core, .NET 5, .NET 6, or later versions. Microsoft documents this requirement in its Power Platform developer tools guide. This is a hard constraint of the Dataverse sandbox runtime.

Can I register a plugin on a custom entity?

Yes. Any entity — standard or custom — can trigger plugins. Custom entities created in Dataverse appear immediately as step targets in the PRT. The same pipeline stages, messages, and image options apply to custom and standard entities alike.

How do I update a registered plugin after changing the code?

Rebuild the assembly in Visual Studio with an incremented version number. Open the PRT, select the assembly node, click Update, and browse to the new DLL. The PRT replaces the stored assembly while preserving all registered steps and images. If you skip the version increment, the update may fail with a version conflict.

What happens if a synchronous plugin throws an exception?

The entire database transaction rolls back. The user sees an error message containing the exception text, and no data is saved. Always throw an InvalidPluginExecutionException with a clear, user-friendly message so end users understand what went wrong. Unhandled exceptions of other types display a generic system error, which frustrates users and generates support tickets.

How many plugins can I register on a single entity?

There is no fixed platform limit on the number of plugins per entity, but practical performance constraints apply. Each synchronous plugin adds latency to the save operation, and the combined execution time of all plugins on a single message must stay under the 2-minute sandbox timeout. If multiple plugins fire on Update of a high-volume entity, review whether some logic can be consolidated or moved to asynchronous execution.


Frequently Asked Questions

Can I register plugins without the Plugin Registration Tool?

Yes. The Power Platform CLI supports scripted plugin deployment, and plugins can be packaged in managed solutions for automated distribution. The PRT remains the standard tool for interactive development and debugging, but CI/CD pipelines typically use the CLI or solution import.

What .NET version do Dynamics 365 plugins require?

Plugins target .NET Framework 4.6.2 or later. They do not run on .NET Core, .NET 5, .NET 6, or later versions. Microsoft documents this requirement in its Power Platform developer tools guide.

Can I register a plugin on a custom entity?

Yes. Any entity, standard or custom, can trigger plugins. Custom entities created in Dataverse appear immediately as step targets in the PRT.

How do I update a registered plugin after changing the code?

Rebuild the assembly in Visual Studio with an incremented version number. Open the PRT, select the assembly node, click Update, and browse to the new DLL. The PRT replaces the stored assembly while preserving all registered steps and images.

What happens if a synchronous plugin throws an exception?

The entire transaction rolls back. The user sees an error message containing the exception text, and no data is saved. Always throw an InvalidPluginExecutionException with a clear, user-friendly message so end users understand what went wrong.

How many plugins can I register on a single entity?

There is no fixed platform limit, but practical performance constraints apply. Each synchronous plugin adds latency to the save operation, and combined execution time of all plugins on a single message must stay under the 2-minute sandbox timeout.


Daniel Harper

Contributor, Dynamics 365 Group

This article is written by Daniel Harper for Dynamics 365 Group. Product behavior, deployment choices, and licensing can change, so confirm current Microsoft documentation before making an implementation decision.

Dynamics 365PluginsPlugin Registration ToolDataversePower PlatformC#.NET

Calculate Your Dynamics 365 Migration ROI

See how much you could save with a free, instant ROI estimate — no signup required.

Get Your Free ROI Estimate