Legacy application modernization means changing existing systems so that they stay supported, secure and cheap to change, without stopping the business processes that run on them. The techniques are well known. For most companies the hard part is deciding the order of work across a portfolio of systems, and in 2026 the Java and Spring support calendar is setting that order for anyone who has not set it themselves.
What is application modernization? Four different jobs
The term application modernization covers everything from a version upgrade to a full replacement of legacy systems, and the four jobs differ in cost and risk by an order of magnitude. Most planning mistakes start with treating them as one.
| Job | When it fits | Typical scale | Main risk | What you keep |
|---|---|---|---|---|
| Upgrade in place | The code is sound, but the runtime, framework and libraries are old or out of support | Weeks per application | Low with tests, high without them | Everything |
| Replatform | The problem is where and how it runs: hosting and containers, or a cloud migration | Weeks to months | Operations change while the code does not | The code, mostly |
| Rearchitect in slices | The design itself blocks change or scale | Months to a year or more | The long middle, when two systems run side by side | The old system, until each slice is replaced |
| Replace | The system no longer fits the business, or a product now does the job | A year or more | One large cut-over | The data, if it migrates cleanly |
Most legacy applications need the first job, and some need the third. The fourth is the one people tend to budget for, because a rewrite is easier to explain than a sequence of upgrades.
Where the security risk sits
The first job is also where most of the security risk sits. Black Duck's 2025 audit of 965 commercial codebases found vulnerable open source components in 86% of them, and components more than four years out of date in 90% (Black Duck OSSRA 2025).
Sonatype found that when a vulnerable component was downloaded in 2024, a fixed version already existed 94.9% of the time (State of the Software Supply Chain).
Veracode's analysis of more than 86,000 repositories found that 92% of flaws in open source libraries could be fixed by an update, and that 69% of those updates were a minor version change or smaller (Veracode, State of Software Security).
For most portfolios, a large part of the risk goes away with upgrades, before any design changes.
The risk of rewriting legacy systems from scratch
Replacement is expensive, and the average cost hides the real exposure. Bent Flyvbjerg and Alexander Budzier studied 1,471 IT projects and found an average cost overrun of 27% (Harvard Business Review).
One project in six overran its budget by 200% on average, and its schedule by almost 70%.
A full rewrite of a core system has the traits of that group: a long period with no production feedback, a fixed cut-over date, and a scope that grows as the team finds behaviour nobody wrote down.
A strategy for transforming legacy systems limits that exposure by splitting the work so that no single piece can overrun on that scale. New code goes live behind a routing layer one slice at a time, which is the strangler fig pattern.
Each slice runs in production before the next one starts. After every slice the company can stop, with a working system and less legacy code, if its priorities change.
When replacing a legacy system is the right call
Replacement is still the right call in two situations: when a packaged product now does the job well enough, and when the data model itself is wrong for the business, so that every slice would carry the old mistake forward. Even then, the data can usually move in stages, one entity or one region at a time.
When to modernize: the Java and Spring support calendar
For Java systems, two sets of dates matter. Every Spring Boot 3.x branch left open-source support on 30 June 2026, and Spring Boot 4.0 follows in December 2026, so a large share of Spring applications already run on a framework that no longer receives free security fixes.
And Oracle's extended support for four Java LTS releases ends within three years: Java 17 in September 2029, Java 8 in December 2030, Java 21 in September 2031 and Java 11 in January 2032.
The full dates, and what Oracle's October 2026 licence change means for JDK 21, are in our Java support calendar. For strategy, the point is simpler: a company that waits for each deadline will meet several of them in the same year, with the same engineers.
A published fix does not upgrade anything on its own. Log4Shell was disclosed in December 2021 and patched within days, yet Sonatype counted about 40 million downloads of vulnerable Log4j versions in 2025, 13% of all Log4j downloads that year (Infosecurity Magazine).
Veracode found that 79% of the time, a library is never updated after it has been added to a codebase. An upgrade happens when it has a place in a team's plan, with a date and a name next to it.
How to assess legacy applications: a portfolio worksheet
The order of work comes from a few facts about each application, and most of them can be collected in about a day per system from tools a team already has. We use the worksheet below at the start of an engagement; a spreadsheet with one row per application is enough.
| Signal | How to measure it | What we treat as high |
|---|---|---|
| Runtime support | JDK version from the build file or the running container; Spring Boot version from the dependency tree | A version past open-source support, or within twelve months of it |
| Known vulnerabilities | A dependency scan: OWASP Dependency-Check, or the scanner already in the pipeline | Any open critical finding, or high findings with no fix planned |
| Tests on the business flows | List the five flows the business depends on and check whether each has an automated test | Fewer than half covered (line coverage from JaCoCo is a hint, not the answer) |
| Change frequency | Commits in the last year: git log --since="12 months ago" --oneline | wc -l | Changes in most weeks |
| Incidents | Pages or incident tickets in the last twelve months | Any repeat incident with the same cause |
| People | Engineers who changed it in the last year: git shortlog -sn --since="12 months ago" | One person, or none |
Support status, vulnerabilities, tests, incidents and people add up to the technical risk of an application. Change frequency, together with what the roadmap says the business will ask for next year, gives the change need. Those two scores place the application on the matrix below.
An application that only one engineer can change is a risk even when every version is current. Pairing a second engineer with that person on its first upgrade reduces both risks at once, and it is often the cheapest item on the whole list.
Application modernization strategy: two questions that set the order of work
An enterprise application modernization strategy does not need a framework with a dozen criteria. Two questions about each system are enough to put them in order.
- How high is its technical risk? Out-of-support versions, open critical vulnerabilities, abandoned libraries and missing tests all count; our guide to technical debt shows how to measure and price them.
- How often does the business need it to change? A system that gets change requests every month pays back modernization quickly. One that nobody touches pays back slowly.
Systems with high risk and frequent change come first: upgrade them, then change the design in slices where it blocks the work. High-risk systems that rarely change need to be made safe, which usually means an upgrade in place and no redesign at all. Low-risk systems that change often can be improved inside normal feature work. The rest can be patched and watched, and revisited when either answer changes. For a whole portfolio, with funding and governance, see our guide to building an IT modernization strategy.
Benefits of application modernization in 2026
For a portfolio of legacy applications, the benefits follow the same order as the work, and they arrive first on the systems the business changes most.
The security benefit is dated: Spring Boot 3.x systems lost free fixes in June 2026, and every advisory published since then raises the cost of staying.
The engineering time comes back more slowly, as upgrades get smaller and unplanned fixes fewer. Readiness for cloud computing and AI tools depends most on the others, because both need the tests and the working build that the earlier steps produce. Our guide to the enterprise cloud covers what running on it well involves.
Lessons from our software modernization projects
We have worked on business-critical Java systems since 2013, and the same four lessons come up on most of our application modernization projects. Each has published evidence behind it, which we cite next to our own work.
Engineering capacity sets the pace
The same engineers who understand the legacy systems have to do the modernization, and most of them are also needed for feature work. The order of work therefore has to be matched against how many of those people are free at the same time, not against the calendar alone.
Part of that time is already being spent, without a plan. In Stripe's 2018 survey of more than 1,000 developers, respondents said they spent 17.3 hours of a 41-hour week, about 42%, on maintenance and bad code (The Developer Coefficient).
McKinsey's 2020 survey of 50 CIOs put the share of new-product technology budgets diverted to tech debt at 10 to 20% (McKinsey).
Both figures are self-reported, but they point the same way: the upgrade work turns up anyway, as unplanned fixes and delays, and an application modernization plan moves some of it into planned, smaller steps.
The arithmetic is simple. Take eight legacy applications that each need an upgrade of two to six weeks of work, and two engineers who can be spared from feature work. That is sixteen to forty-eight engineer-weeks, or two to six months of calendar time before anything else on the list moves. Doing the same sums for the whole portfolio, with honest estimates, usually shows whether the plan fits before 2029 or needs more people.
Two habits keep this manageable. The first is an upgrade train: stay within one release of current for the framework and the JDK, so each upgrade is small and none of them turns into a project. The second is to fold small upgrades into normal iterations instead of saving them for a dedicated programme that never gets approved.
For scale, we moved a fifteen-year-old online store and back-office ERP from Java 17 and Spring 5.3 to Java 25 and Spring 6.2 in about four weeks, without a feature freeze; the case study shows the steps.
Small batches have the strongest evidence behind them
Google's DORA research programme has found, year after year, that teams who work in small batches and merge to a shared trunk through continuous integration deliver faster and more reliably (DORA, working in small batches). Its thresholds are concrete: three or fewer active branches, merges to trunk at least once a day, and no code freezes or integration phases (DORA, trunk-based development).
DORA also notes that small batches stop an organization from falling into the sunk-cost fallacy, a risk that is sharper in a migration than in feature work.
Applied to app modernization, the rules look like this:
- Migration work merges to the main branch every day, behind a feature flag or a routing rule, instead of living on a branch for months.
- Each step moves one major version of one of the key technologies: the JDK, the framework or the build tool, never all of them in one change.
- Each step is deployed to production before the next starts, so a regression points to a small diff.
- Feature work continues on the same branch, which keeps the migration visible to everyone who touches the code.
For a Spring application on Boot 2.7, that means Boot 3.0 first, with Java 17 as the new baseline and the move from javax to jakarta packages, then the later 3.x releases, then Boot 4.0. OpenRewrite publishes recipes for these moves, and each step is days to a few weeks of work on a typical service. Going from 2.7 to 4.0 in one change combines all of them into a diff that nobody can review properly.
What the first month should produce
The first month of an app modernization project should leave you with things you can check, not a slide deck:
- An inventory of each application, which is the worksheet above filled in: runtime and version, framework and version, build tool, test coverage and the people who can change it.
- A dependency scan baseline, so progress on vulnerabilities can be measured.
- Characterization tests around the flows the business depends on, written before anything moves. Michael Feathers named them in Working Effectively with Legacy Code: tests that record what the system does today, including behaviour that looks wrong, so that any change to it shows up as a failing test.
- One completed upgrade or slice running in production, which proves the pipeline and the approach.
- A written order of work for the rest of the portfolio, placed on the two questions above.
How to tell a modernization is stalling
Modernization efforts rarely fail in one moment. They slow down until the company is paying for two systems and progress on neither. The early signs are measurable:
- No old code has been deleted in a month.
- The share of traffic served by new code has stopped rising.
- Feature work has been frozen "until the migration is done".
- The scope is drifting from upgrades towards a rewrite.
- The dependency scan shows the vulnerability count rising again.
Most of these signs come from batches that have grown too large, and the usual fix is to cut the next step smaller. If a programme shows two or more of them, the order of work needs revisiting before more budget goes in. In an acquisition, the same questions belong in technical due diligence, and for systems that simply need to keep running, a support retainer can carry the upgrades.
AI tools in app modernization: the mechanical work, not the decisions
Automated refactoring tools and AI coding assistants now do a real share of the upgrade work in app modernization, and three large engineering organizations have published numbers on it.
Published results from Google, Amazon and Airbnb
Google used a language model to migrate 32-bit identifiers to 64-bit across its monorepo: 39 migrations by three developers over twelve months. The model generated 74% of the code changes that were submitted, and the developers estimated that the work took about half the time of earlier manual migrations (Migrating Code At Scale With LLMs At Google).
Every change was still reviewed by a person, and about a quarter of them had to be written by hand.
Amazon reports that its code transformation agent cut the average upgrade of an application to Java 17 from about 50 developer days to a few hours, moved more than half of its production Java systems in under six months, and saved an estimated 4,500 developer-years; developers shipped 79% of the generated changes without edits (Andy Jassy, August 2024). These are company figures from a vendor describing its own product.
Airbnb migrated about 3,500 React test files from Enzyme to React Testing Library in six weeks, against an internal estimate of 18 months by hand. 97% of the files were migrated automatically, and engineers finished the rest starting from the model's output (Airbnb Engineering).
The three cases have the same shape. The change was narrow and defined in advance, a build and a test suite checked every result automatically, and people reviewed what was merged.
On the wine merchant upgrade, automated refactoring moved more than 800 files to the new Jakarta namespaces, and every change was still reviewed. Our guide to AI-assisted application modernization covers the tools and the review gates in detail.
Where AI makes modernization efforts worse
Without those conditions the results are worse. DORA's 2024 report estimated that every 25% increase in AI adoption was associated with a 1.5% drop in delivery throughput and a 7.2% drop in delivery stability (Accelerate State of DevOps 2024), and its 2025 report describes AI as an amplifier of an organization's existing strengths and weaknesses (DORA 2025).
Which library to replace, which behaviour change is acceptable and which system to leave alone this year are still decisions for someone who knows the system and the business. The tests are what make any tool safe to use, because they show whether a change kept the behaviour the business depends on.
Legacy application modernization rulebook: six rules to follow
The sections above come down to six rules. We check an application modernization plan against them before it starts, and again whenever one of the stalling signs appears.
- Upgrade before you redesign. Most known vulnerabilities in legacy applications have a fix in a newer version, so the first job on the list removes most of the risk at the lowest cost.
- Order the work by risk and change need. Place each system on the two questions above and start top right; a system nobody changes needs a safe version, not a new design.
- Write characterization tests before anything moves. Tests on the flows the business depends on are what make every later step, and every tool, safe to use.
- Move one version of one thing per step. One major version of the JDK, the framework or the build tool per change, deployed before the next, keeps each regression to a small diff.
- Keep feature work going. A freeze "until the migration is done" is one of the stalling signs; migration work belongs on the main branch next to feature work.
- Let tools do the mechanical work, and keep the decisions with people. Recipes and AI assistants handle narrow, well-defined changes; which library to replace and which system to leave alone stay with someone who knows the business.
If you want a second opinion on your own order of work, our application modernization services start there: the first step of the Application Modernization Sprint produces a written inventory, the order of work and a ballpark estimate, within a week of a thirty-minute call.