D365 F&O Extension Rationalisation: What to Rip Out, Replace With an ISV, or Leave Alone
I reviewed a D365 Finance & Operations estate last quarter that carried 43 bespoke X++ extensions. The client had been live for two years. Every quarter service update cost roughly GBP 25,000 in regression testing and consumed three weeks of internal capacity. Nobody on either the client or partner side could remember why some of the extensions had been built.
That is the moment a CFO usually calls me. Not to admire the architecture. To ask why the bill keeps growing.
This article is a practical playbook for extension rationalisation in D365 F&O. Not a theoretical framework. A four-step process you can run against your own estate over a quarter, with measurable cost reduction at the end of it.
Step 1: Build the inventory
Start with a complete inventory of every X++ extension in production. Class extensions, form extensions, table extensions, event handlers, chain-of-command overrides, custom services. Your LCS code packages and the build pipeline give you the file-level list, but the inventory has to go further.
For each extension, capture what it does in plain business language, which standard D365 object it modifies, when it was first deployed, who requested it, and whether it was part of the original design or added during hypercare. That last point is the most predictive. Extensions added in the first 12 weeks after go-live, when nobody had time to think clearly, are the ones most likely to be rationalisable.
If your inventory does not exist, the first phase of any rationalisation programme is building it. Two weeks of effort. Worth it.
Step 2: Classify against four buckets
Once the inventory is complete, sort each extension into one of four buckets.
Remove. The extension was built for a process that no longer exists, a workaround for a Microsoft bug that has since been patched, or a feature that duplicated standard functionality the original team did not know about. In a mature estate I typically find 15-25% of extensions sit here. They survived because nobody audited.
Replace with configuration. The partner reached for X++ when D365 already had the capability standard. I see this most often with custom workflows that duplicate the standard Workflow framework, custom number sequences that re-implement the Number Sequence engine, custom validation logic that a Posting Validation Rule or a Financial Reason Code would handle, and custom approval routing that the standard module supports if configured properly.
Replace with ISV or Power Platform. The extension addresses a real business need but a supported ISV product or a Power Automate flow can do the same job without bespoke code. Document management, advanced bank reconciliation, intercompany allocation engines, procurement governance, contract management. These are the areas where a productised solution usually beats a custom build over a five-year horizon. The licence fee buys you out of the regression testing burden.
Keep. The extension addresses a genuinely organisation-specific requirement that no configuration, ISV or Power Platform solution can meet. These are worth maintaining. Typically 40-60% of the inventory. The point of rationalisation is not to drive custom code to zero. It is to eliminate the code that should never have been written.
Step 3: Prioritise by risk and cost
Not every extension carries equal risk. Two factors should drive sequencing.
The first is regression frequency. Extensions that touch posting routines, batch jobs, or high-volume forms are the ones most likely to break during a service update. An extension on a rarely used setup form carries a fraction of the risk of one that modifies the General Ledger posting engine.
The second is partner dependency. Extensions that require partner involvement to test, debug or update after every service update should be prioritised for replacement. The goal is to shrink the regression scope to the point where your internal team can own each update cycle without external help. That is where the GBP 25,000 every quarter goes away.
Step 4: Execute in phased waves
Do not try to remove twenty extensions in a single sprint. Run rationalisation as a phased programme across two or three service update cycles. Five to eight extensions per cycle is realistic. Test in tier-2, validate through a RSAT pass, deploy in the next standard update window.
A note on RSAT, the Regression Suite Automation Tool. It is underused on most projects I see. If you do not have automated regression coverage of your critical finance and operations processes (month-end close, AP invoice posting, sales order to cash, inventory close), build that coverage before you start removing extensions. Removing extensions without a safety net is how you turn a rationalisation programme into a recovery programme.
What good looks like
The clients who manage their estate well share two habits. They run a "build vs configure vs buy" check on every proposed extension during design and require sign-off from an independent architect before X++ is approved. And they audit the extension inventory once a year, not once an update breaks something.
The ones who do not are the ones still paying GBP 25,000 every quarter for a regression cycle that grows longer with every wave.
What to do next
If your D365 F&O estate has accumulated extensions and nobody has audited which ones are still earning their keep, an independent rationalisation review can identify the candidates for removal, replacement and retention, and quantify the cost reduction. We run these as standalone engagements: Solution Blueprint Review (Independent) | Dr Dynamics
For weekly D365 F&O architecture analysis, subscribe at Dr Dynamics Newsletter
Or email sales@drdynamics.co.uk to discuss your extension estate.