Low-Code, SaaS Config, and ERP Debt
Last updated . Sources are named and dated inline - how we source claims.
Some of the largest technical debt balances in any enterprise sit inside platforms the engineering organisation does not consider software at all.
Nobody writes a post-mortem about a workflow rule. But the configuration inside your CRM, your ERP, and your service management platform is executable logic that decides what the business does -- usually with no version control, no review, no tests, and no owner.
Configuration Is Code, Without Any of the Safety Rails
A validation rule that blocks an order. An approval chain that routes a discount. A formula field that feeds a revenue report. A flow that creates records in three objects when a case closes. Each of these is a conditional statement with side effects, executed in production, affecting money. That is code by any definition that matters.
What it usually lacks is everything the industry spent thirty years learning to put around code. There is no branch, no pull request, no reviewer, no automated test, and frequently no non-production environment where the change could have been tried first. The change is made by clicking, in the live system, by whoever holds the admin role that afternoon. There is no commit message, so there is no reason recorded. There is no diff, so there is no before and after.
The result is a peculiar kind of debt that is simultaneously enormous and invisible. It does not show up in a static analysis report, a dependency scanner, or an engineering roadmap, because none of those tools can see inside the platform. It shows up as a quarter-close that takes two weeks, a sales process nobody can explain, and an upgrade that gets deferred for a fourth consecutive year.
The Line Between Configuration and Customisation
Every packaged platform draws a line. On one side is configuration: options the vendor anticipated, expressed through supported settings, which the vendor commits to carrying forward across releases. On the other side is customisation: code and modifications that reach past the supported surface into behaviour the vendor never promised to preserve.
Crossing that line is not automatically wrong. Sometimes the business genuinely does something the platform does not model, and the choice is between a customisation and not being able to operate. What is wrong is crossing it without recording that you did, because the cost is not paid at build time. It is paid at every future upgrade, forever, by people who were not in the room.
SAP's clean core guidance states the principle plainly: "Any modification to the ERP functionality offered by SAP is built outside of the core, using extensibility solutions." Every major vendor says some version of this, and the reason is always the same. Modifications inside the core are what turn a routine vendor release into a project.
Upgrade Debt: The Customisation That Blocks a Release
Packaged platforms move on a schedule you do not control. Salesforce publishes three major releases a year that arrive whether you are ready or not. On premise ERP moves the other way, through long maintenance windows that eventually expire: SAP has said it will provide mainstream maintenance for core SAP Business Suite 7 applications until the end of 2027, followed by optional extended maintenance until the end of 2030. Either shape produces the same pressure: a date exists, and your modifications have to survive it.
ServiceNow makes the mechanism unusually visible. When an upgrade would touch a record you have altered, the platform does not overwrite it -- it skips it and writes a skip log entry, leaving a list of every customisation that has now diverged from the new baseline. The documentation is blunt about the consequence: "Post-upgrade, thoroughly test all changes you made to the records on the skipped records list." That list is a literal, itemised statement of the interest due on customisation debt, regenerated at every upgrade.
Most organisations never read the list as a debt register, which is exactly what it is. Each entry is a decision someone made years ago that now has to be re-examined, re-tested, and either merged forward or reverted to baseline. When the list is long enough, the rational-looking response is to defer the upgrade -- and deferral is how a platform ends up several versions behind, unable to adopt features already paid for, and eventually facing a migration instead of an upgrade.
The Export Problem: Nobody Can Answer "What Changed?"
In a normal codebase, "what changed last week and who approved it" takes seconds to answer. Inside many configured platforms it is genuinely unanswerable. Logic lives in database rows, in drag-and-drop canvases, in expression fields, or in a proprietary serialisation that was designed to be moved between environments rather than read by a human.
Where an export exists, it is often not reviewable in any meaningful sense. A generated file may reorder elements between exports, embed environment-specific identifiers, or encode the whole thing as one long line, so the diff shows hundreds of changed elements when a single condition actually moved. A reviewer facing that diff cannot approve it on the merits; they can only approve the person. Graphical flows are worse, because the meaningful change may be a reconnected arrow that no textual representation captures well.
This is the root cause behind most of the other problems on this page. Without a readable diff there is no review; without review there is no gate; without a gate every other control is advisory. Any platform assessment should therefore start with a blunt question: can we produce a human-readable, order-stable representation of this configuration, and can a second person understand a change from it? If the answer is no, you cannot govern that platform through review, and you will have to govern it through environments, approvals, and audit trails instead.
Citizen-Developer Sprawl
Low-code platforms succeeded at their stated goal: thousands of people who are not developers now build things that run every day. The debt is in what nobody planned for -- what happens to those things afterwards.
The Maker Who Left
An app or flow is usually owned by the individual who built it, not by a team or a function. When that person changes role or leaves, the asset keeps running with an owner who no longer exists in any practical sense. Nobody knows what it does, nobody can safely turn it off, and the first sign of trouble is a process quietly failing months later.
You Cannot Fix What You Cannot List
The first governance task is always inventory, and the platforms know it. Microsoft's tenant-level Power Platform inventory exists to give administrators "a unified view of all agents, apps, and flows built on Power Platform across their organization", and lists preventing orphaned resources owned by departing users as an explicit purpose. Equivalent administrative views exist on most major platforms. Very few organisations use them.
Even the Inventory Has Caveats
Read the fine print before trusting a report. Microsoft notes that the owner column for cloud flows "shows the user who created the flow" and "doesn't update when the owner changes". An inventory that silently reports a stale owner is worse than none, because it produces confident, wrong answers. Validate what each field actually means before you route work based on it.
No Handover Ritual Exists
Engineering has offboarding conventions: repositories transfer, on-call rotations update, ownership files change. Business-built automation has none of that, because it was never registered as an asset in the first place. Adding ownership transfer to the standard leaver process costs almost nothing and prevents the single most common failure mode on these platforms.
Integration Debt and Point-to-Point Sprawl
Every configured platform ends up connected to the others, and almost none of those connections were designed. A connector here, a scheduled export there, a flow that writes into a second system using someone's personal credentials, a nightly file drop that three downstream reports silently depend on. Each was the shortest path to solving one problem on one afternoon.
Collectively they form an undocumented distributed system with no diagram, no contract, and no error handling worth the name. Nobody can say what breaks if a field is renamed, because the dependency exists only inside a connector configuration nobody has opened in two years. Credentials belong to individuals rather than services, so an account deactivation takes out a business process. When something fails at three in the morning, the failure surfaces as a wrong number in a report rather than as an alert.
Treat these connections as interfaces with owners and contracts, exactly as you would a service boundary in your own architecture. Register them, name a responsible team, use service identities rather than personal ones, and make failures loud. The concerns are the same ones covered in our guide to API debt -- versioning, contracts, and the cost of coupling -- with the added difficulty that these interfaces were never announced to anyone.
Lock-In Through Proprietary Logic
Lock-in on these platforms is rarely about data. Data can usually be exported. What cannot be exported is the logic: the rules, the routing, the calculations, and the process decisions that were expressed in a proprietary flow designer or a vendor-specific scripting language. That material has no portable representation, so it does not migrate -- it gets rebuilt from scratch, by people reverse-engineering the current behaviour of a system nobody documented.
This is why platform migrations consistently cost more than the business case predicted. The estimate is anchored on data volume and licence cost, both of which are knowable. The actual work is rediscovering years of accumulated business rules that exist only as configuration, and deciding which of them are still deliberate. The same dynamic makes acquired-company platform estates so expensive to consolidate, a pattern explored further in our guide to acquisition debt.
You cannot eliminate this exposure while getting the benefit of a packaged platform, and pretending otherwise leads to expensive abstraction layers that satisfy nobody. What you can do is bound it: keep genuinely differentiating logic where it is portable, prefer supported extension points over deep in-platform scripting, and maintain a plain-language description of critical processes that is independent of the tool implementing them. If the only accurate specification of how your business prices a deal is a flow diagram in one vendor's designer, that is a strategic dependency, not a configuration detail.
From Shadow IT to Business Critical, Without an Adoption Step
The characteristic low-code failure is not a bad build. It is a good one. Somebody in operations builds a small tool that solves a real problem. It works, so a colleague starts using it. A manager builds a report on top of its output. A customer-facing process comes to depend on it. At no point does anyone decide that this is now a production system, because there is no moment at which that decision is presented to anybody.
So it accumulates every property of a critical system and none of the obligations. No backup strategy, no test environment, no access review, no documentation, no monitoring, no second person who understands it. It may hold personal data that never appeared in a privacy assessment. It may implement a financial control that an auditor has never seen. The organisation is exposed to it in exactly the way it would be exposed to an unreviewed production deployment, but no control was ever bypassed, because no control was ever in scope.
The remedy is not to forbid this -- the tools exist because central delivery could not meet demand, and banning them recreates the original problem while pushing it further out of sight. The remedy is a graduation path: a lightweight, well-publicised route by which something that has become important gets adopted, reviewed, given an owning team, and brought under normal operational care. Make that path genuinely easy, because if graduation is more painful than staying hidden, everything stays hidden.
Governance That Actually Works
Governance fails on these platforms when it is designed as a gate on creation. The people building are not asking permission, so a policy they never read cannot bind them. What works is tiering by consequence.
Tier by Blast Radius
A personal productivity app needs no ceremony. Something touching customer data, money, or a regulated process needs review, an owning team, and an environment strategy. Publish the criteria so makers can place their own work, and make the light tier genuinely light.
Inventory Continuously
Run the tenant-level inventory on a schedule and diff it, rather than commissioning an audit every few years. Growth and abandonment are both signals. Know the caveats behind each field, and confirm ownership with a human rather than trusting a stale column.
Ownership on Teams
Assign every consequential asset to a function, never to a person, and wire ownership transfer into the standard leaver process. Most orphaned automation is created by an ordinary internal move that nobody connected to a running system.
Fund Retirement
Nothing is ever deleted because deletion has no sponsor and carries all the risk. Give someone the explicit job of retiring unused assets, with a defined notice period, and the estate stops growing without limit. Our governance and policy guide covers the wider framing.
Getting Configuration Under Source Control
Where the platform supports it, this is the single highest-value change available, and the vendors themselves now say so. Salesforce's developer experience guidance is explicit: "Instead of the org, your version control system is the source of truth." Microsoft's application lifecycle management guidance for Power Platform says the same thing -- "Source control should be your source of truth for storing and collaborating on your components" -- and identifies solutions as the mechanism for moving components between environments.
That reframing is the whole point. When the repository is authoritative and the org is a deployment target, every practice that was impossible becomes ordinary: a change is a commit with an author and a reason, a reviewer sees a diff, a pipeline promotes it through environments, and the production system can be rebuilt rather than only patched. It also gives you the artifact that every audit, incident review, and upgrade needs, which is a truthful record of what the configuration was on a given date.
Do not attempt the whole estate at once. Start with the platform whose configuration exports most cleanly, and inside it with the objects that carry the most business risk. Establish the pipeline for those, prove it survives a real release, then widen. Where a platform genuinely cannot produce a reviewable export, be honest that source control is not available and compensate with environment separation, approvals, and audit logging instead of pretending a policy document is a control. The dependency-hygiene mindset in our dependency management guide transfers directly.
Related Resources
Governance & Policy
Turning standards into controls people actually follow, including tiering by consequence rather than gating everything equally.
Dependency Management
Staying current with platforms and components that move on their own schedule rather than yours.
API Debt
Contracts, versioning, and coupling -- the same problems your undocumented platform connectors have, with better vocabulary.
Acquisition Debt
What you inherit when two configured platform estates have to become one, and why consolidation estimates are always low.
Frequently Asked Questions
Configuration is not debt by itself, any more than code is. It becomes debt through the same mechanism: decisions that made local sense, accumulated without record, that now constrain what you can change. A validation rule is a conditional with side effects running in production. When there is no reviewer, no test, no owner, and no way to see what changed, you have all the liabilities of a codebase with none of the tooling. That gap is the debt, and it is usually larger inside packaged platforms than in the code the engineering team writes.
The vendor draws it, and the practical test is what they commit to carrying forward across releases. Supported settings and sanctioned extension points are configuration; modifications reaching past that surface are customisation, and the vendor owes you nothing when the underlying behaviour changes. SAP's clean core guidance puts it directly: any modification to the ERP functionality SAP offers should be built outside the core using extensibility solutions. Crossing the line is sometimes justified. Crossing it without recording the decision and its reason is what makes it expensive later.
Start with the platform's own administrative inventory rather than a survey. Microsoft's tenant-level Power Platform inventory is built to give administrators a unified view of the agents, apps, and flows across the organisation, and comparable admin views exist elsewhere. Then read the caveats: Microsoft notes that the owner column for cloud flows shows who created the flow and does not update when ownership changes, so a report can look authoritative and still be wrong. Run the inventory on a schedule, diff it, and confirm ownership with a person before you act on it.
Only two routes exist. Where the platform can produce a stable, human-readable export, put it in source control and the question becomes a diff, which is why both Salesforce and Microsoft now tell customers to treat version control rather than the live org as the source of truth. Where it cannot, no amount of policy will manufacture an answer, so you compensate: separate environments, approvals that record who asked and why, restricted production admin rights, and platform audit logs retained long enough to be useful. Decide which situation each platform is in, and stop assuming the first.
No, and attempts to do so mostly relocate the problem somewhere less visible. These tools grew because central delivery could not meet demand, and that demand does not disappear when you publish a prohibition. Tier instead. Let low-consequence work happen with no ceremony at all, and reserve review, team ownership, and environment discipline for things touching customer data, money, or regulated processes. Then provide an easy graduation path for anything that outgrows its original scope, because the real risk is not that people build -- it is that something important stays informal indefinitely.
On the major platforms, yes, and it is the highest-value change available. Salesforce exposes org configuration as retrievable metadata and its developer guidance treats the version control system rather than the org as the source of truth. Microsoft's Power Platform guidance names solutions as the mechanism for moving components between environments and likewise says source control should be your source of truth. Do not attempt the whole estate at once: start with the platform that exports most cleanly and the objects carrying the most business risk, prove the pipeline through a real release, then widen.
Start With the Inventory
You cannot govern, retire, or migrate what nobody has listed. Every other fix on this page depends on knowing what exists and who owns it.