The Commerce Runtime (CRT) is the backbone of Dynamics 365 Commerce business logic. Every operation the POS performs — reading a product, calculating a price, placing an order — flows through a CRT pipeline. Understanding how these pipelines work is the foundation of reliable D365 Commerce development.
What is a CRT pipeline?
A CRT pipeline is a sequence of request/response handlers that process a specific operation. When the Store Commerce app needs to fetch customer information, it creates a GetCustomerDataRequest and submits it to the CRT. The runtime locates all registered handlers for that request type and executes them in order.
Each handler can:
- Pre-trigger: run logic before the default handler executes
- Override: replace the default handler entirely
- Post-trigger: run logic after the default handler completes
This three-phase model gives you precise control without needing to copy-paste Microsoft's original code.
Writing your first extension handler
The cleanest way to extend a pipeline is with a post-trigger. Here's a minimal example that adds a custom attribute to every GetCustomerDataResponse:
[Export(typeof(IRequestTrigger))]
public class CustomerPostTrigger : IRequestTrigger
{
public IEnumerable<Type> SupportedRequestTypes =>
new[] { typeof(GetCustomerDataRequest) };
public async Task OnExecuted(Request request, Response response)
{
var customerResponse = (SingleEntityDataServiceResponse<Customer>)response;
var customer = customerResponse.Entity;
// Add your custom logic here — e.g. fetch from an external system
customer.SetProperty("CustomLoyaltyTier", await GetLoyaltyTier(customer.AccountNumber));
}
public Task OnExecuting(Request request) => Task.CompletedTask;
private async Task<string> GetLoyaltyTier(string accountNumber)
{
// Call your external loyalty service
return "Gold";
}
}
Registering your handler
Extensions are registered via commerceruntime.ext.config. Add your assembly reference:
<composition>
<add source="assembly" value="Contoso.Commerce.Runtime.Extensions" />
</composition>
The CRT discovers handlers through MEF composition — no manual wiring required.
Common pitfalls
Async all the way down. CRT handlers are async by design. Blocking on async calls with .Result or .GetAwaiter().GetResult() inside a handler will deadlock under load. Always await properly.
Don't break the pipeline. If your pre-trigger throws an unhandled exception, the entire request fails. Wrap external calls in try/catch and decide whether a failure should be fatal or gracefully degraded.
Respect upgrade boundaries. Only extend via the documented extension points — never modify Microsoft assemblies directly. Changes in sealed types will break on every platform update.
Testing your handlers
Microsoft provides a CommerceRuntimeConfiguration test harness that lets you unit-test handlers in isolation without a full Retail Server instance. Set up a minimal configuration that includes only your extension assembly and the request types you depend on — this keeps tests fast and deterministic.
CRT extensions are one of the most powerful tools in the D365 Commerce developer's toolkit. Once you understand the pipeline model, most customisation requirements become straightforward to implement cleanly.
If you're working through a complex CRT scenario — custom pricing logic, external system integration, or a tricky CDX sync issue — feel free to reach out.