Every software team pays for technical debt, but few can say how much. Without a number, paying it down competes with features on opinion and loses.

This guide defines technical debt, sorts it into the types that cost money in a Java system, and shows how to measure it, price it and reduce it, including the point at which paying it down piecemeal stops working.

Technical debt definition

Ward Cunningham coined the term in 1992: "Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite. ... Every minute spent on not-quite-right code counts as interest on that debt" (OOPSLA 1992 experience report).

In business terms, technical debt is the gap between how a system is built and how it would need to be built to change cheaply today. It has two parts:

  • Principal: the one-off effort to close the gap, such as an upgrade, a refactoring or a missing test suite.
  • Interest: the extra cost paid on every change, incident and audit while the gap stays open.

Debt is not always a mistake. Martin Fowler's technical debt quadrant sorts it along two axes, deliberate or inadvertent and reckless or prudent. Shipping a known shortcut to meet a launch date, with a plan to fix it, is prudent and deliberate. Learning after a year in production how the design should have looked is prudent and inadvertent, and Fowler argues it is "inevitable for teams that are excellent designers". The debt to worry about is the debt nobody decided to take and nobody tracks.

The aggregate is large. CISQ estimates the accumulated technical debt in US software at about $1.52 trillion, within a total cost of poor software quality of at least $2.41 trillion (CISQ, 2022). In Stripe's survey of developers, 13.5 hours of a 41.1-hour working week went on technical debt (Stripe, The Developer Coefficient).

Types of technical debt

The types differ in how visible they are and how fast the interest grows. In long-lived Java systems, the expensive ones are rarely the messy methods developers complain about.

TypeWhat it looks like in a Java systemHow the interest shows up
Code debtDuplicated logic, thousand-line classes, dead code pathsSlower changes in the affected files
Design and architecture debtModules that call each other's internals, one schema shared by everything, synchronous call chainsEvery change touches several areas and needs several teams
Dependency and platform debtJava 8 or 11, Spring Boot 2.7 or 3.x out of open-source support, javax namespaces, an old WebLogic or JBoss serverUnpatched vulnerabilities, extended support fees, an upgrade that grows every year
Test debtNo automated tests around pricing, billing or other critical rulesFear of change, long manual regression, defects found in production
Build and infrastructure debtManual deployments, snowflake servers, a build only one person can runSlow, risky releases and long recovery from failures
Knowledge debtRules that live only in the code and in one engineer's headEverything stops when that person is away

Dependency and platform debt deserves the most attention because it is the only type with a fixed due date. Code debt gets more expensive gradually; a framework leaving support turns into a security problem on a known day.

Technical debt examples from Java systems

  • A store on an unsupported framework. An online wine merchant we worked with ran its store and back office on Java 17 and Spring 5.3, which no longer received open-source fixes, with 12 critical and 35 high-severity vulnerabilities in its dependencies. Moving it to a supported Java and Spring stack took about four weeks, without splitting the application (case study).
  • Vulnerable libraries that have fixes. Vulnerable versions of Log4j still made up 13% of all Log4j downloads in 2025, four years after Log4Shell, and roughly 95% of vulnerable component downloads had a fixed version available (Sonatype). That is dependency debt in its purest form: the fix exists, the upgrade work has not been done.
  • The javax to jakarta rename. A Spring application that stayed on Spring Boot 2.x now carries the Jakarta EE namespace change, the Spring Security 6 configuration changes and two Spring Boot majors in one upgrade.
  • Dead code in production. Knight Capital lost more than $460 million in about 45 minutes in 2012 after a deployment reactivated an old, unused code path; our legacy system modernization guide tells the story.

Platform debt has a due date

For Java systems, the support calendar turns dependency debt into a schedule. Every Spring Boot 3.x branch left open-source support on 30 June 2026, and Oracle's extended support for Java 17 ends in September 2029.

Support end dates seen from October 2026. Spring Boot 3.x open-source support ended in June 2026, with commercial support to June 2032; Spring Boot 2.7 open-source support ended in June 2023, commercial to June 2029. Oracle extended support ends for Java 17 in September 2029, Java 8 in December 2030, Java 21 in September 2031, Java 11 in January 2032 and Java 25 in September 2033; Java 17 premier support ended in September 2026 and Java 21 premier support runs to September 2028.WHEN THE PLATFORM DEBT FALLS DUE20262028203020322034Spring Boot 3.xcommercial to June 2032Spring Boot 2.7commercial to June 2029Java 17extended to Sep 2029Java 8extended to Dec 2030Java 21extended to Sep 2031Java 11extended to Jan 2032Java 25extended to Sep 2033October 2026free or premier supportpaid extended or commercial support only
Java and Spring Boot support end dates as of October 2026 (Oracle Java SE support roadmap, Spring Boot support). After the teal bar, fixes cost money; after the amber bar, there are none.

Each version a team skips adds to the principal: one minor Spring Boot upgrade is days of work, three majors at once can be months. Our Java end-of-life dates and Spring Boot 4 migration guides list the dates and the upgrade paths.

How to measure technical debt

No single number captures technical debt. Four groups of measures, most of which a team already has, cover it well enough to price and track.

Dependency age and support status

List every runtime, framework and library with its version, the latest version and its end-of-support date. Track the share of components on supported versions and the months until the next support deadline. Most codebases score badly here:

Black Duck's open source security and risk analysis of commercial codebases: 93% contain components with no development activity in the last two years and 92% contain components four or more years out of date (2026 report); 86% contained open source vulnerabilities (2025 report); only 7% of components in use are the latest versions (2026 report).OPEN SOURCE IN COMMERCIAL CODEBASES0%25%50%75%100%No development in two years93%Four or more years out of date92%Known vulnerabilities86%Components on latest version7%
Open source components in audited commercial codebases; vulnerabilities from the 2025 report, the rest from 2026 (Black Duck OSSRA 2026, 947 codebases; Black Duck OSSRA 2025).

Known vulnerabilities

Count open vulnerabilities by severity from a software composition analysis scan, and track how long a critical one stays open. Separate the ones fixed by a patch release from the ones that need a major upgrade: the second group is platform debt showing up as security risk.

Delivery metrics

Debt slows delivery before anyone measures it in code. DORA's five delivery metrics show it: change lead time ("the amount of time it takes for a change to go from committed to version control to deployed in production"), deployment frequency, change fail rate, failed deployment recovery time and deployment rework rate. A lead time that grows quarter after quarter while the team size stays the same is interest being paid.

Code-level signals

Static analysis gives a code-level view. SonarQube's technical debt ratio is "the ratio between the cost to develop the software and the cost to fix it" (SonarSource). Use it for trends rather than as an absolute figure, and weight it by change frequency: debt in a file nobody touches costs no interest. The hotspots that matter are files that are both complex and changed often, which git log shows in minutes.

The cost of technical debt: a simple model

Technical debt gets budget when it has a yearly cost next to it. The model below prices the interest from four inputs most teams can estimate in a day; the numbers are an example for a team of eight engineers, not a benchmark.

Interest itemHow to estimate itExample
Slower changesShare of engineering time spent working around debt × team hours × hourly cost20% × 8 × 1,700 h × €60 = €163,200
IncidentsIncidents a year caused by debt × hours to resolve × hourly cost, plus business impact12 × 30 h × €60 = €21,600
Extended supportPaid support for runtimes and frameworks past their free supportOracle prices Java SE Universal Subscription per employee, from $15 a month in its smallest band
Security remediationHours spent mitigating vulnerabilities that an upgrade would remove200 h × €60 = €12,000

Compare the yearly interest with the principal, the estimated effort to remove the debt. If an upgrade costs 16 engineer-weeks (about €38,400 at the same rate) and removes most of €197,000 of yearly interest, it pays back within a quarter. Debt whose principal exceeds several years of interest can wait, unless it has a due date.

How to reduce technical debt without a feature freeze

Feature freezes for "cleanup sprints" rarely survive the next deadline. Paying down debt continuously works better:

  • Reserve a fixed share of capacity. Accenture found that leading companies target 15% of IT budgets for keeping technical debt in balance (Accenture). Make it a standing line in every iteration, not a negotiation.
  • Upgrade on the vendor's cadence. A minor Spring Boot upgrade every six months is a routine task; skipping two years of them is a project.
  • Automate the mechanical part. OpenRewrite recipes handle most of a framework upgrade's import, configuration and API changes, leaving people to review the result and fix what the recipes cannot.
  • Add tests before touching a hotspot. Characterization tests around a pricing or billing rule make the refactoring that follows safe.
  • Delete dead code. Code that never runs still has to be compiled, scanned and upgraded.
  • Stop adding new debt. A dependency bot, a module boundary test and a definition of done that includes tests cost little and keep the principal from growing.
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
  -Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:RELEASE \
  -Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5

The command above applies OpenRewrite's Spring Boot 3.5 upgrade recipe to a Maven project; the UpgradeSpringBoot_4_0 recipe takes the next step to Spring Boot 4.

When technical debt remediation needs a modernization project

Continuous paydown works while the interest is moderate and the principal fits into a few iterations. These signs mean it no longer does:

  • A runtime or framework leaves free support within a year, and the upgrade path crosses more than one major version.
  • Critical vulnerabilities stay open because fixing them needs a major upgrade.
  • Change lead time has doubled over two years with the same team size.
  • More than a third of each iteration goes to unplanned work and workarounds.
  • One or two people are the only ones who can change a business-critical module.
  • The architecture forces every change through several teams, and modularizing it is a project of its own (our guide on monolith to microservices migration covers that route).

At that point the debt needs its own plan: an inventory, a priced list of the work and an order to do it in. Our application modernization guide covers how to sequence it.

The Application Modernization Sprint starts with a thirty-minute scoping call and a written ballpark within a week. The first iteration maps your Java system's versions, vulnerabilities and support dates, and prices the debt before any upgrade starts.