
Separate configuration from customization, see how SAP and Odoo document their extension routes in pages we could open, and get questions for reviewing each custom request plus the clauses that belong in a TOR.
Suppose a company has run its ERP for three years. The vendor announces a new version that closes a security hole and adds a function accounting has been waiting for. IT asks the developer to estimate the upgrade, and the answer comes back split into several phases, because a sales-order report changed two years ago overwrites the standard logic, and there are scripts that write straight into data tables in several more places. None of the executives who approved those changes remember asking what it would cost next time to keep them alive.
This article is written from the viewpoint of a team that designs and delivers systems, and it is addressed to the business owner or project sponsor who has to decide how much customization of an ERP to allow. We separate two terms that are often used interchangeably, configuration and customization, explain what two vendors whose documentation we could actually open say about the matter, and propose a way to review each custom request along with the clauses that belong in a TOR. The examples are hypothetical throughout and do not refer to any particular organization.
Two terms that get mixed up
In project meetings, the word customization tends to cover everything that is not the system's default. But the two kinds of work have very different long-term costs.
Configuration means setting the system through the switches, options, tables and tools the vendor designed for adjustment: chart of accounts, approval chains, document layouts, user permissions. The vendor knows this part exists, and the next version is designed to carry the values you set.
Customization means adding or changing code where the vendor did not prepare a slot: a report that pulls data straight from internal tables, a step inserted into the middle of a standard process, or edits to the product's own code. This work may be genuinely necessary, but the vendor does not promise it will keep working in the next version.
Between the two sits a middle ground called an extension, which adds capability through connection points the vendor announces and maintains. That middle ground is where we would like most requests to land, because it delivers the business-specific need without touching what the vendor may change without notice.
What the vendors actually say
ERP vendors take different approaches, so we use two examples whose documents we could read, and we do not claim every product behaves the same way.
SAP publishes a concept called clean core in SAP Learning courses. One page states that SAP guarantees the stability of interfaces declared as released from one release to the next, and that customers following the approach agree to use only released interfaces in new developments and extensions. The development tools raise an error when an unreleased object is called. The example on that page is reading a country data table directly, where the tool tells you to use a CDS entity SAP provides instead (see the Exploring Released APIs page on SAP Learning).
Another page in the same course describes four levels of extension. Level A uses released APIs and is the level SAP says gives the greatest upgrade stability. Level B uses classic APIs and technologies. Level C reaches into internal objects, which the page says carries manageable risk. Level D uses objects that are not recommended, including modifications and direct writes to SAP tables, which the page describes as the highest risk and as technical debt. The same page says internal objects can change without notice or compatibility guarantees, and recommends extending at the highest level possible (see the Extensibility Model Best Practices page).
Odoo is a different kind of product. Its developer documentation teaches extending the models and views of an existing module through inheritance instead of overwriting the original view in place, and says to call super() when overriding a method so the original flow is not broken (see Odoo's tutorial on inheritance). That page does not discuss upgrade cost directly. We cite it only to show that another vendor also provides an extension route separate from editing core code.
One limit has to be stated plainly. We could not open SAP's full 2024 white paper on clean core extensibility, because the server refused the request, and an ASUG article summarizing the latest guidance is open to members only. What we describe above comes only from the SAP Learning course pages, and we have not checked whether the level definitions in the full white paper match the course wording. We also have no figure for how much the upgrade bill differs between a lightly customized system and a heavily customized one, and we will not give one in this article.
What makes upgrades expensive
From what the two vendors' documents describe and from what systems teams find when they take over an existing system, we see five factors that can turn an upgrade into a new project.
Edits live inside the vendor's code. When the vendor ships a new version, our edits have to be compared and merged back one spot at a time, and nobody guarantees the spot we changed is still where it was.
Direct writes to data tables. A script that bypasses the system's own mechanisms to change data also bypasses its validation rules and event logging, and the table structure is something the vendor can change.
Calls to things the vendor has not announced. The SAP material cited above calls this group internal objects and says they may change without notice.
Undocumented reports and interfaces. Work the previous person wrote, with nobody knowing which department uses it, gets discovered when it breaks after the upgrade, not before.
No repeatable test suite. If post-upgrade testing means users clicking through screens one by one, the cost of testing rises with every added customization, and that cost is usually left out of the price when the customization is approved.
The fifth point connects to what we wrote in our article on release management on production: every change should pass a repeatable test, not depend on what the people in last month's meeting happen to remember.
Reviewing each custom request
We suggest that every request that is not a setting provided by the vendor answer the following questions in writing before it is approved.
Can this need be met with configuration? Ask the developer to show that the standard options were checked and cannot do it, not merely to say they are not familiar with the option.
If it is built as an extension, does it use a route the vendor announces? Ask for the name of the API or connection point used and a link to the vendor's documentation.
Does it write to tables or call internal objects? If so, record it as an exception with the reason and the name of the approver.
What does the business lose if this is not built? An answer that is real pain in the process should outweigh the answer that users are used to the old system working that way.
Who maintains it after handover? If it is a single developer, ask who can read this code once that person is gone.
The next time the vendor releases a version, what has to be done to keep this alive? Ask the developer to estimate it as a range of work. An exact figure is not required, but it should distinguish between just running the test suite and rewriting.
The last question is the one we would like approvers to ask every time, because it changes the decision from the price of building to the price of living with it. That is the same idea as in our article on whether to rewrite or refactor a legacy system, which argues that the real cost of a system lies in keeping it going.
What to write into the TOR
If you are still procuring or renewing, the following clauses tie to things that can be verified in the system and do not depend on a product name or version.
All extensions must use the routes the product vendor announces in its documentation. Direct writes to tables, edits to core code, and calls to objects the vendor has not announced must be approved case by case, in writing.
The developer must deliver an inventory of customized objects, stating what each does, which route it uses and who owns it on the business side, updated whenever one is added or changed.
Each time the vendor releases a new version, a test round against that inventory is required and its results go to the client before the upgrade is applied to the live system.
Agree in advance who pays for that test round, and whether fixes caused by customizations outside the announced routes fall under the maintenance contract or count as separate work.
The test suite for the customized parts is part of the handover, so whoever takes over can run it again.
The details of what kind of requirements make a system maintainable are in our article on conditions in a TOR, and how to fit upgrade rounds into an annual maintenance contract is covered in our article on annual maintenance contracts.
What not to do
In our view there are three things to avoid.
The first is refusing every customization just because you read an article like this. A system that does not let the business work the way it really works will be bypassed with spreadsheets and off-system steps, which carry invisible costs of their own. The second is handing the entire decision to the developer. The developer can assess technical risk, but the person who knows which process matters to the business is the process owner. The third is believing that using an announced route means no testing is needed after an upgrade. An announced route lowers the chance of breaking, but it does not guarantee that the business logic we wrote on top of it is still correct in the new version. The vendor guarantees the interface, not your process.
Limits we should state plainly
Some businesses genuinely need deep customization, for example a production process or a calculation that the standard product does not have at all. If you are in that group, the goal is not to forbid customization but to fence it and price it honestly: separate the customized part clearly, give it an owner and a test suite, and put the cost of living with it into the budget from the first day. Also, if you use a SaaS ERP in which the vendor already does not let you edit code, most of this article's core problem does not arise for you, though the questions about extensions and integrations with other systems still apply.
One more limit: we can only confirm what the SAP Learning pages and Odoo's developer documentation state. We have not checked other vendors' documents, and each product defines what counts as a supported extension differently. Before writing clauses into a TOR, ask your vendor to point out what its announced routes are.
Objections we often hear
A common objection is that the vendor itself customizes for clients, so why should we worry. That is partly right. Customization is normal in ERP projects, but the question we would like asked is which route it goes through and who is responsible when the next version arrives. If the answer is clear and written into the contract, customization can be managed.
Another is that we never upgrade, we can stay on this version forever. That can work for a while, but vendors tend to stop issuing security patches for old versions eventually. We do not know the schedule of any particular product, so we suggest asking the vendor directly how long your version is supported and recording the answer. Postponing an upgrade does not remove the cost. It moves it into a single lump on the day postponing is no longer possible.
Where to start
Ask for the list of everything customized in the system you run today. If there is no list, ask the developer to produce a first version. Incomplete is still better than none.
Sort each item into configuration, an extension through an announced route, or an internal edit, and see how many items fall in the last group and who uses them.
Ask the vendor how long your current version is supported, and record the answer with the date.
Pick the one or two riskiest items and have the developer write a repeatable test for them first, before changing any code.
Add the six questions above to your request approval process, and adjust the TOR or maintenance contract at the next renewal.
Summary
The SAP Learning pages say that announced interfaces are stable from one release to the next and that internal objects may change without notice, and Odoo's documentation teaches extending through inheritance rather than overwriting. If you take one thing from this article, ask of every customization request: next time the vendor ships a new version, what has to be done to keep this alive, and have the developer answer in writing before approval.
If you would like to talk through the details of a project, you can reach us at 088-983-9386 or [email protected]. Our office is in Bang Kapi, Bangkok. For organizations still drafting a scope of work, we are glad to arrange a conversation to understand the problem first, without needing complete documents. And if we find that the problem is not yet at the point of needing a new system, we will say so plainly, because starting a project at the wrong time costs more than waiting another quarter.
FAQ: Frequently Asked Questions about This Article
A collection of questions and answers to help you better understand the content of this article.
Tags:

