Building Better Commands in D365: JS + Actions + Power Automate
In my previous post, I discussed a silent failure scenario involving a JavaScript-triggered Action + Plugin setup. This post explores a more structured approach using JavaScript + Action + Plugin, and how to scale it with Power Automate. Architecture Overview This approach separates responsibilities cleanly between: Client: JavaScript Logic: Plugins Integrations: Power Automate Step 1: JavaScript as the Initiator We start with a JavaScript function that triggers a bound action, keeping the UI lightweight and offloading processing to the server. Xrm.WebApi.online.execute({ entityName: "quote", entityId: quoteId, actionName: "new_CustomWinQuoteAction" }); Step 2: Custom Action as a Dispatcher The Custom Action serves as a reusable interface layer that: Accepts input parameters Supports versioning and audit Can be triggered from JavaScript, Power Automate, or other Plugins Step 3: Plugin for Business Logic A plugin is registered on the Custom Action step to handle the core business logic. public void Execute(IServiceProvider serviceProvider) In this method, you retrieve the context and execute operations like cloning records, creating tasks, or updating fields. This ensures critical logic stays within the Dynamics 365 execution context. Step 4: Power Automate for Scalability For operations involving delays, external APIs, or heavy workloads, we offload tasks to Power Automate. Common trigger methods include: HTTP request from the Plugin Azure Service Bus message Custom API endpoint Ideal use cases: Sending emails or Teams notifications Interacting with third-party services Logging or telemetry Plugin vs Power Automate Comparison Aspect Plugin (C#) Power Automate Execution Fast, synchronous Asynchronous CRM Context Full access Limited context and impersonation control Integration Complex setup Easy third-party integration Use Case Secure, governed, critical logic Non-critical, long-running tasks Real Example: Clone and Notify Pattern JavaScript triggers the CloneAndNotifyAction. The Custom Action receives the Opportunity ID. A Plugin: Clones the Opportunity Creates follow-up tasks Sends an HTTP payload to Power Automate Power Automate: Sends notification emails Logs the operation in SharePoint Conclusion This layered pattern enables you to: Separate logic between frontend, backend, and external services Reuse business logic across multiple entry points Scale with Power Automate without overloading Plugins If you're designing custom commands or ribbon buttons in Dynamics 365, this approach ensures flexibility, testability, and long-term maintainability.

In my previous post, I discussed a silent failure scenario involving a JavaScript-triggered Action + Plugin setup. This post explores a more structured approach using JavaScript + Action + Plugin, and how to scale it with Power Automate.
Architecture Overview
This approach separates responsibilities cleanly between:
- Client: JavaScript
- Logic: Plugins
- Integrations: Power Automate
Step 1: JavaScript as the Initiator
We start with a JavaScript function that triggers a bound action, keeping the UI lightweight and offloading processing to the server.
Xrm.WebApi.online.execute({
entityName: "quote",
entityId: quoteId,
actionName: "new_CustomWinQuoteAction"
});
Step 2: Custom Action as a Dispatcher
The Custom Action serves as a reusable interface layer that:
- Accepts input parameters
- Supports versioning and audit
- Can be triggered from JavaScript, Power Automate, or other Plugins
Step 3: Plugin for Business Logic
A plugin is registered on the Custom Action step to handle the core business logic.
public void Execute(IServiceProvider serviceProvider)
In this method, you retrieve the context and execute operations like cloning records, creating tasks, or updating fields. This ensures critical logic stays within the Dynamics 365 execution context.
Step 4: Power Automate for Scalability
For operations involving delays, external APIs, or heavy workloads, we offload tasks to Power Automate. Common trigger methods include:
- HTTP request from the Plugin
- Azure Service Bus message
- Custom API endpoint
Ideal use cases:
- Sending emails or Teams notifications
- Interacting with third-party services
- Logging or telemetry
Plugin vs Power Automate Comparison
Aspect | Plugin (C#) | Power Automate |
---|---|---|
Execution | Fast, synchronous | Asynchronous |
CRM Context | Full access | Limited context and impersonation control |
Integration | Complex setup | Easy third-party integration |
Use Case | Secure, governed, critical logic | Non-critical, long-running tasks |
Real Example: Clone and Notify Pattern
- JavaScript triggers the
CloneAndNotifyAction
. - The Custom Action receives the Opportunity ID.
- A Plugin:
- Clones the Opportunity
- Creates follow-up tasks
- Sends an HTTP payload to Power Automate
- Power Automate:
- Sends notification emails
- Logs the operation in SharePoint
Conclusion
This layered pattern enables you to:
- Separate logic between frontend, backend, and external services
- Reuse business logic across multiple entry points
- Scale with Power Automate without overloading Plugins
If you're designing custom commands or ribbon buttons in Dynamics 365, this approach ensures flexibility, testability, and long-term maintainability.