In this article (9 sections)
The budget for a build gets argued over for weeks. The cost of keeping it running afterwards almost never gets discussed, and it's the one you pay every year for the whole life of the system.
As an industry reference, annual maintenance of custom software lands between 15% and 20% of the development cost. On a USD 15,000 system, that's USD 2,250 to 3,000 a year. The number is useful for budgeting, but it explains nothing: it doesn't say what you're paying for or why it varies so much. Here's the breakdown.
The four costs, separated
Putting them all in one bag labelled "maintenance" is what makes the conversation confusing. They're four different things, with different logic.
1. Infrastructure
The system runs somewhere and that somewhere bills monthly. Server, database, file storage, domain, certificates, email delivery service.
For a small or mid-size system, USD 20 to 200 a month depending on volume. It's the most predictable of the four and the one that gives the fewest surprises.
What does surprise people: it scales with usage, not with features. A system that hasn't changed in two years can double its infrastructure bill because the company grew.
2. Bug fixing
The errors. The ones that show up in production, with real data, in situations nobody tested.
The curve is fairly stable: most of it appears in the first two or three months and then drops sharply. That's why almost any serious contract includes a 3 to 6 month warranty on what was delivered, where this isn't billed separately.
It's worth being clear about what's covered and what isn't, because this is where the typical argument happens. A button that doesn't save is a bug: covered. A report sorted by date when you wanted it by customer, if the spec said date, is a change: not covered.
3. Updates and security
This is the most underestimated one, because the system works exactly as well whether or not the maintenance was done. There's no visible symptom until there's a serious problem.
A build sits on dozens of third-party libraries that publish security patches, new versions and, every so often, changes that break compatibility. If nobody touches them for three years, updating stops being routine and becomes a project.
A system that isn't maintained doesn't degrade: it accumulates. And the bill comes due in full the day someone has to touch it.
Same with integrations: if your system talks to a bank, to a tax filing service or to a payment platform, those APIs change on their decision and their calendar, not yours. A version change with a deadline isn't negotiable.
Budget for it even if nothing happens. It's exactly the kind of expense that gets cut in year one and paid triple in year four.
4. New work
What you add because the company changed: a new report, one more field, a process that now has an extra step, an integration that didn't exist before.
It's the only one of the four that is optional and proportional to what you want to do. It's also, in most living systems, the biggest of the four. It isn't maintenance in the strict sense: it's new development on top of a base that already exists.
For this, the healthy way to contract is usually a monthly block of hours, because the scope genuinely can't be defined in advance.
What pushes the number up
Two systems at the same price can have very different maintenance costs. What makes the difference:
- How many integrations. Every external system you talk to is a dependency that can change without warning you. It's the heaviest factor.
- Concurrent users and data volume. It moves infrastructure and, past a certain point, forces optimization work.
- How much business logic it has. A system with pricing rules, commissions and approvals has more surface where something can go wrong than a CRUD.
- How old the chosen stack is. A build done on technology that was already on its way out starts with debt on day one.
- Whether there are automated tests. Without tests, every small change means testing half the application by hand. You pay for it on every modification, forever.
That last point is the one worth looking at before signing a build, not after.
The three ways to contract it
A block of hours. You buy a monthly package and it gets consumed against whatever you ask for. It's the most common and the most flexible. Always ask whether unused hours roll over or expire.
A fixed monthly fee. A monthly amount covering infrastructure, bug fixing and updates, with new work billed separately. It gives predictability and it works when the system is critical to the operation.
Per incident. You pay nothing until something happens. It's the cheapest on paper and the most expensive when it matters: with no active relationship, whoever picks up the phone has to re-learn a system they haven't touched in a year, and that gets billed.
For a system that holds up the daily operation, "per incident" is a false economy. For a secondary internal tool, it can be perfectly reasonable.
The questions worth asking before you sign the build
Not after. The cost of maintaining is set by decisions made while it's being built.
- How long is the warranty and what exactly does it cover?
- Does the code end up in my name, in a repository I have access to?
- What happens if I want someone else to maintain it? Is there documentation so another team can pick it up?
- Are there automated tests? What coverage?
- Is the infrastructure in my name or the vendor's?
- What versions of the main dependencies does it use, and how long are they supported?
The third and the fifth are the most uncomfortable and the most important. A system only the people who built it can maintain, running on an account you don't control, is not an asset of yours. It's a subscription with exactly one possible vendor, and that vendor sets the price.
The number, again
Back to the 15-20% a year: it works as an order of magnitude for budgeting, but build it up in parts. Infrastructure you can quote exactly. Bug fixing should be under warranty for the first six months. Updates are a fixed floor you have to keep paying. New work is a business decision, not a technical cost.
A system that doesn't evolve isn't a cheap system. It's almost always one that stopped keeping up with the company, and that's the step before replacing it entirely.