Modernizing Packaged & On-Prem Software Products
Modernizing a packaged or on-prem software product is harder than modernizing a SaaS product because the vendor does not control where the software runs. One aging codebase is deployed across many customer environments at once — different operating systems, database versions, hardware, and product releases — and every one of those installs is a live system under a support contract you cannot break. You cannot freeze the product, because customers expect releases; you cannot cut everyone over at once, because they upgrade on their own schedules; and you cannot bet the company on a big-bang rewrite, because up to 70% of digital transformations fail their objectives (BCG, September 2023). The realistic path is to modernize the shipping product slice by slice, prove each slice behaves identically before it reaches a customer, and ship it as an ordinary release — so the product keeps working in the field the entire time.
There is a series alongside this one about modernizing a SaaS product — a multi-tenant application the vendor runs in a cloud it controls. This series is its mirror, written for the other kind of software company: the independent software vendor whose product is installed. You ship it. The customer runs it — on their servers, their desktops, their operating systems, behind their firewall. The same codebase you maintain in one place is deployed and live in dozens or hundreds of environments you do not control. That single difference changes the modernization problem completely, and it is the reason this series exists separately from the SaaS one.
The codebase is still the product — but you don’t run it
In a SaaS company the codebase is the product, and the company runs the one copy that matters. For a packaged or on-prem ISV the codebase is still the product, but the running copies belong to customers. You author one artifact; it lives as many deployments, each on its own hardware, its own database version, its own OS patch level, its own product release. You cannot log into them. You cannot see them all. You cannot change them in place. And every one of them is a production system that someone is paying you to keep working.
That is the constraint that defines on-prem modernization, and it removes the escape hatches a SaaS team takes for granted. A SaaS team can re-platform a slice behind a single deployment and no customer ever needs to know. An on-prem vendor cannot — anything that changes has to travel out as a release, get installed by the customer on their schedule, and behave correctly in an environment the vendor has never seen. The modernization happens in your codebase, but it has to land in environments you do not own.
Version sprawl: the on-prem tax
The most expensive consequence of shipping installed software is version sprawl. Customers upgrade when it suits them — some run the current release, some are two versions back, some are on a build from years ago that they have validated against their own compliance regime and refuse to touch. So at any moment the vendor is supporting not one product but a spread of releases, each multiplied by the environment combinations it runs on: operating system, database engine, runtime version, hardware.
Every one of those combinations is something you have to be able to reproduce a bug against, patch a vulnerability in, and regression-test before you ship. The test surface is the product of releases times environments, and it grows faster than the team. This is the tax SaaS simply does not pay — a SaaS company runs one version in one environment and deprecates the rest. An on-prem ISV carries the whole spread, and it is usually the single largest hidden cost in the business. Reducing it is one of the strongest reasons to modernize toward more uniform, more current delivery, a thread this series follows through and prices out in Part 7.
Why you can’t do the three obvious things
When the codebase feels old, three instincts surface. For an installed-software vendor, all three are traps.
You can’t freeze the product. Customers under maintenance contracts expect releases — fixes, compatibility updates, the occasional feature. A modernization that stops the release train breaks the implicit deal of the support contract and hands competitors an opening. The roadmap, such as it is, has to keep moving.
You can’t cut everyone over at once. Even if you build something modern, customers install it on their own timelines. There is no flag you can flip to move the whole base to a new version overnight; migration is a population you move gradually, with the old releases still alive in the field the entire time. Any plan that assumes a single coordinated cutover is a plan that ignores how installed software actually reaches customers.
You can’t bet the company on a rewrite. The seductive move — declare the codebase bankrupt and rebuild it clean — is the most dangerous option available to a product business. A multi-year rewrite freezes the roadmap, asks the company to wager its customer base on a project that delivers nothing until the end, and carries the failure rate that makes it the riskiest thing in software: BCG found in September 2023 that up to 70% of digital transformations fail to deliver on their objectives. For a vendor whose customers can leave at renewal, a stalled or broken rewrite is not a setback — it is an extinction event. The big-bang rewrite trap is the specific failure this series is built to avoid.
The debt is real, and it compounds
None of this means the aging is imaginary. Installed-software codebases accumulate the same compounding technical debt as any other — shortcuts built on shortcuts, dependencies sliding toward end-of-life, the original engineers gone and their reasoning with them. The drag is measurable: Stripe’s 2018 research put the share of developer time lost to debt and bad code at roughly 42% (The Developer Coefficient), and McKinsey’s October 2020 analysis estimated technical debt at 20–40% of an entire technology estate’s value. For an ISV that drag is doubled, because debt does not just slow the roadmap — it inflates the cost of supporting every version in the field, since brittle code is harder to patch safely across the environment spread.
So the pressure is genuine and it builds. The question is never whether to modernize a product customers still depend on. It is how to do it without breaking the installs that pay the bills.
The shape of the answer
The path that works is the same one the SaaS series arrives at, adapted for software you ship rather than software you run. You modernize the product slice by slice. You isolate a coherent piece of the codebase behind a stable interface, build its modern replacement, and prove it behaves identically to the old code — same outputs, same behavior, edge cases included — before it reaches a single customer. Then it ships inside an ordinary release, indistinguishable to the customer from any other update, and the old code is retired once the new slice has proven itself in the field. The pattern underneath is the strangler fig: the modern product grows up inside the old one, a slice at a time, until the legacy code can be removed — with no point at which the product stops working in a customer’s environment.
This is what lets a product vendor modernize a shipping product without a destabilizing big-bang release. Each slice is small, validated, and reversible; the blast radius of any release is one slice, not the whole product; and the version customers run keeps behaving the way they expect throughout. Parity validation — proving the new slice matches the old before it ships — is what makes that safe rather than hopeful, and it matters more for installed software than anywhere else, because once a broken release is sitting in a customer’s environment you cannot quietly roll it back the way a SaaS team can.
Where the discipline is more than the product needs
Slice-by-slice is the right default for a product customers depend on, but it is not free. It carries overhead a rewrite does not: maintaining the seams, validating each slice against the environment spread, keeping the product shippable throughout. For a tiny product with one or two customers that could be rebuilt and re-deployed in a few weeks, that discipline may be more than the situation warrants. The method earns its keep precisely when the product is too widely installed, too valuable, or too contractually load-bearing to risk a big-bang — which describes most established ISVs.
Where this leads
The frame is now set: an installed-software vendor ships one aging codebase into many environments it does not control, pays a version-sprawl tax SaaS avoids, and cannot freeze, cannot cut over at once, and cannot safely rewrite — so the work has to happen slice by slice on a product that stays live in the field. The natural next question is what you are usually modernizing, architecturally, because most installed products share a common shape. Part 2, Modernizing Client-Server Architecture, looks at the architecture most packaged products are built on and the signs it has reached its limit.
Frequently asked questions
- How is modernizing on-prem software different from modernizing SaaS?
- The vendor does not control the runtime. A SaaS company modernizes code running in one environment it operates; an on-prem ISV ships one codebase into many customer environments it does not control — varied operating systems, database versions, hardware, and product releases, each under its own support contract and upgrade schedule. That removes the SaaS escape hatches: you cannot quietly re-platform behind a single deployment, you cannot cut all customers over at once, and you must keep older field releases working while you modernize. Modernization has to ship as ordinary, low-risk releases that behave identically to what customers already run.
- Can you modernize a shipping software product without a big-bang rewrite?
- Yes — and for a product customers depend on, the big-bang rewrite is the option to avoid. The alternative is to modernize the codebase slice by slice: isolate a coherent piece behind a stable interface, build its modern replacement, prove it behaves identically to the old code against real inputs, and ship it inside a normal release. Each slice is independent, validated, and reversible, so the product keeps working in every customer environment throughout and you are never one risky cutover away from breaking installs in the field.
- Why is version sprawl across customer installs such a problem for ISVs?
- Because every release still running in the field is a release you have to support, reproduce bugs against, and keep secure. When customers upgrade on their own schedules, the vendor ends up maintaining many versions of one product at once across many environment combinations, which multiplies test surface, support cost, and the risk that a fix for one customer breaks another. Version sprawl is the on-prem tax that SaaS avoids by running a single deployment — and reducing it is one of the strongest financial arguments for modernizing toward modern, more uniform delivery.