Technical Debt: How to Measure It and When Paying It Down Is Worth It
Technical debt is the most used and least measured metaphor in engineering leadership, and the reason it resists measurement is that the metaphor is wrong in a specific way: there is no principal balance, no fixed interest rate, and no maturity date. What exists instead is a capacity tax. Some parts of a codebase make every change that touches them slower and more likely to break, and that penalty is paid continuously, in engineering time, whether or not anyone has named it. This distinction is not pedantic. It determines what an organization should measure, because a balance cannot be measured but a tax rate can, and it determines when paydown is worth funding, because a tax is only worth eliminating where it is actually being levied. A great deal of code carries what engineers would call debt and imposes no cost at all, because nobody touches it. This guide covers what technical debt actually is, the proxy metrics that measure the tax, why dedicated debt sprints fail so reliably, how to frame the argument for a finance leader, what AI-assisted development changes, and when the correct decision is to leave it alone.

Key Takeaways
- The financial metaphor breaks in three places: there is no principal to pay off, no fixed rate, and no due date. What can be measured is the ongoing tax, meaning how much slower and more failure-prone work becomes in a given area, which is a rate rather than a balance.
- Only one of the four common situations is genuinely debt. Deliberately accepting a shortcut to ship sooner is a financing decision. Code that is bad because nobody knew better, or because standards slipped, is not debt but rot, and it should be argued for on different grounds.
- The proxies that work are outcome metrics plus location metrics. Change lead time and change failure rate say how heavy the tax is; hotspot analysis, meaning files with both high churn and high complexity, says where it is being collected. Neither alone is actionable.
- Allocating a fixed percentage of capacity to debt fails predictably, because it creates a parallel backlog with no owner and no provable value, and it is the first thing cut under pressure. Paydown attached to feature work in the same area survives, because the team is already there and the value is immediate.
- The strongest argument to a finance leader is a capacity tax expressed as a percentage of engineering spend, with a payback period. Framed as code quality it competes with features and loses. Framed as a recurring cost with a one-time removal price, it becomes an ordinary investment decision.

What Technical Debt Actually Is
The standard framing distinguishes deliberate from inadvertent decisions and prudent from reckless ones, producing four situations that get called the same name and deserve different responses.
Deliberate and prudent. The team understands the correct design, chooses a shortcut to meet a real deadline, and knows what was traded. This is the only quadrant that is genuinely debt, and it is a legitimate financing instrument: shipping three months earlier can be worth far more than the cost of the rework.
Deliberate and reckless. The team knows better and skips the work with no deadline forcing it. Not debt, a process failure.
Inadvertent and prudent. The design was reasonable given what was known, and building it revealed a better approach. Not debt, learning. Nearly all long-lived systems accumulate this and no amount of discipline prevents it.
Inadvertent and reckless. The team did not know what good looked like. Not debt, a capability gap, and refactoring without addressing the gap produces the same result again.
The practical value of the distinction is that it stops one argument from being used for four different problems. A leader who hears "technical debt" and funds a refactor is sometimes funding a rework of a deliberate trade, sometimes paying for a hiring mistake, and sometimes paying for learning that could not have been avoided. Those warrant different conversations.
Why the metaphor misleads
Three properties of financial debt do not carry over, and each one causes a specific management error.
There is no principal. Nobody can state the number that would clear it, because the target is a moving definition of good and because most of a system could be improved indefinitely. Asking engineering to quantify the balance produces a fabricated number.
There is no fixed rate. Financial debt accrues predictably. This accrues only when someone touches the affected code. A module with terrible internals that nobody has modified in three years charges nothing. The same module under active development charges heavily. The interest rate is a function of change frequency, which is the single most useful correction to the metaphor, because it says where to look.
There is no maturity date. Nothing forces settlement. Systems run for decades in a state engineers describe as unacceptable, and much of what is called debt is never repaid and never needs to be, because the code is deleted or the product is retired first.
What remains true and useful is the direction of the analogy: taking on some now to move faster is rational, and taking on unlimited amounts eventually consumes capacity. The error is treating it as a balance sheet item rather than an operating expense.

The Proxy Metrics That Work
Since the balance is unmeasurable, measure the tax. Two categories are required, and organizations that adopt one without the other end up with numbers they cannot act on.
Outcome metrics say how much the tax costs in aggregate. Location metrics say where it is being collected. Outcome metrics without location tell a leader things are slow but not what to fix. Location metrics without outcome tell a team where the ugly code is without establishing that it costs anything.
| Metric | What it captures | Where it comes from |
|---|---|---|
| Change lead time | Elapsed time from code committed to running in production; rises as a codebase becomes harder to change safely | Version control plus deployment pipeline timestamps |
| Change failure rate | Share of deployments causing degradation or requiring remediation; rises with coupling and weak test coverage | Incident records correlated with deploys |
| Time to restore | How long recovery takes when something breaks; reflects observability and rollback capability as much as code quality | Incident tracking |
| Hotspot score | Change frequency multiplied by complexity, per file or module; identifies where difficult code is also actively worked | Version control history plus static analysis |
| Onboarding time to first meaningful change | Weeks before a new engineer ships something non-trivial; a direct measure of comprehensibility | Engineering records, tracked per team |
| Dependency freshness | How far behind current versions the dependency tree sits; predicts forced-migration cost and security exposure | Dependency scanning tooling |
| Rework rate on recent changes | Share of changes modified again within a short window; indicates changes that did not hold | Version control history |
| Test coverage on hotspots only | Whether the risky, frequently changed code is protected; global coverage is a vanity metric by comparison | Coverage tooling scoped to the hotspot list |
Hotspot analysis deserves particular emphasis, because it operationalizes the insight that the interest rate depends on change frequency. Complexity alone identifies code that is hard to work with; churn alone identifies code that is worked on constantly. The product of the two identifies where an organization is actually paying, and that intersection is typically a small fraction of the codebase. Most estates concentrate the great majority of the tax in a handful of modules, which is what makes targeted paydown viable rather than hopeless.
Two cautions. These metrics are diagnostic, not evaluative: the moment lead time becomes a target teams optimize the measurement rather than the system. And the tail matters more than the median, since a team with a good average lead time and a long tail is describing exactly the subsystems where debt lives.
Knowing which team owns a hotspot is a prerequisite for acting on any of this, which is one of the underrated arguments for the ownership registry described in what a service catalog is. A hotspot with no clear owner does not get fixed.
Why Dedicated Debt Time Fails
The standard prescription is to reserve a fixed share of capacity, commonly twenty percent, for technical debt. It fails consistently, for four structural reasons rather than for lack of discipline.
It creates a parallel backlog. Debt items accumulate in a separate list competing against features on a different axis, with no shared prioritization. Anything on that list is by construction less urgent than anything on the main one.
It is the first thing cut. When a deadline compresses, the twenty percent becomes ten, then zero, and does not return, because nothing external forces it back.
Its value is unprovable. A team that spends a sprint on debt cannot demonstrate what improved, since the counterfactual is invisible. Work that cannot show results loses funding.
It does not slow the deposit rate. Feature work continues creating debt at the same rate, so a fixed allocation is bailing at a constant rate against inflow that scales with delivery.
What works instead
Attach paydown to feature work in the same area. When a team is building in a module, refactoring it is cheap, because the context is already loaded, the tests are already being run, and the change is already being reviewed. The same refactor done cold costs several times more. This is the highest-leverage scheduling rule available.
Target hotspots, not the worst code. The instinct is to fix what offends most. The correct target is what costs most, meaning high churn and high complexity together. Ugly code with no churn is free to leave alone.
Budget it inside the estimate. If a feature touching a hotspot is estimated at three weeks and the estimate includes cleaning the area it touches, the paydown ships with the feature and is never separately cancellable.
Reserve dedicated time only for work that cannot be incremental. Some things do not decompose: replacing a framework, splitting a database, removing a dependency threaded through everything. These need explicit funding as projects with defined outcomes, not a standing allocation. They should be rare and individually justified.
Set a floor, not a ratio. Rather than twenty percent of everything, require that hotspot count and change failure rate do not worsen quarter over quarter. That is a constraint teams can meet in whatever way fits their work, and it fails loudly.
How to Talk About It to a CFO
The argument fails in finance conversations for a specific reason: it is usually presented as a quality problem, and quality competes against features on a scale where features win. Reframing solves most of the difficulty.
Express it as a capacity tax with a percentage. Not "this code is bad" but "changes touching this subsystem take roughly forty percent longer and fail three times as often, and it was touched in sixty percent of last quarter's work." That is a recurring cost expressed in engineering capacity, which converts directly to money.
Give the removal a price and a payback period. "Eliminating that penalty costs eight engineer-weeks and returns roughly three engineer-weeks per quarter thereafter" is an ordinary investment case. It can be compared against other uses of the same eight weeks, and it can lose that comparison legitimately.
Be explicit about what happens with no action. The honest answer is usually not collapse but gradual deceleration: feature throughput declines quarterly while headcount stays flat, which finance eventually observes as declining engineering productivity without a cause attached.
Use forced-migration events as anchors. An unsupported dependency, an expiring platform version, or a compliance requirement converts optional work into scheduled work with a deadline. These are the easiest cases to fund and should be identified early, when the runway is long.
Connect it to valuation where relevant. For any organization facing acquisition, fundraising, or a strategic transaction, code quality becomes a diligence line item with real pricing consequences, as covered in technical due diligence. Debt that costs velocity internally can cost multiple externally, and that argument reaches an audience the capacity argument does not.
The deeper cost case, including attrition and security exposure, is developed in the real cost of technical debt. The measurement discipline here is what turns that case into a specific number for a specific subsystem.
What AI-Assisted Development Changes
Two effects are real, they operate in opposite directions, and which dominates is an organizational choice rather than a property of the tools.
The creation rate goes up. More code is produced per engineer per week, and code volume correlates with maintenance burden. More consequentially, generated code is frequently accepted with shallower comprehension than code an engineer wrote line by line. Code that works and is not understood by anyone on the team is debt by the most useful definition, regardless of how clean it looks. Review becomes the bottleneck, and review under volume pressure degrades toward approval. The productivity picture and its caveats are examined in AI coding assistants and productivity.
The paydown cost goes down. The work debt paydown consists of is close to ideal for these tools: mechanical refactoring, generating tests for untested code, writing documentation for undocumented modules, migrating between framework versions, and applying a repetitive change across many files. Work that was previously uneconomic because it was tedious rather than difficult is now cheap.
The net depends entirely on where the productivity gain is spent. An organization that converts all of it into feature output accumulates debt faster with no offsetting paydown. One that routes some of it to the hotspot list gets both. The tools do not decide this, and defaulting produces the first outcome, since feature demand is always present and paydown demand is always deferrable.
One caution specific to this moment: generated tests for existing code lock in current behavior, including current bugs. They are valuable as a refactoring safety net and should not be mistaken for validation that the behavior is correct.
When Not to Pay It Down
| Situation | Action | Why |
|---|---|---|
| High churn, high complexity | Fix, attached to the next feature touching it | This is where the tax is actually levied; the payback is fastest and provable |
| High churn, low complexity | Leave it; monitor | Frequently changed and easy to change is a healthy state, not a problem |
| Low churn, high complexity | Leave it; document the boundary | Ugly and untouched charges nothing; refactoring spends real money to remove a cost of roughly zero |
| Low churn, low complexity | Ignore entirely | No signal here |
| Scheduled for retirement or replacement | Do not touch beyond keeping it running | Every hour invested is written off on the decommission date |
| Stable, working, nobody assigned | Leave it; keep dependencies patched | Security exposure is a separate obligation from debt paydown and should be funded separately |
| Blocking a specific committed roadmap item | Fix, and fund it as part of that item | The cost is now attached to a business outcome with a date |
| Forced by an unsupported dependency or compliance deadline | Fix, scheduled early | The deadline is external; the only variable is whether it is done with runway or in a panic |
| Being divested, sunset, or wound down | Freeze | The acquirer or the calendar owns the consequence |
The pattern across the table is that debt is only worth paying where it is charging interest, and interest requires activity. The most common misallocation in well-intentioned programs is spending heavily on the low-churn, high-complexity quadrant, because that is where the code looks worst and where the offense to engineering sensibility is greatest.
The same discipline applies to architectural decisions more broadly: act on measurement rather than anticipation, and split or rebuild only when a defined trigger fires. The consolidation framing in Postgres as the everything database is the same reasoning applied to system boundaries, where premature splitting buys complexity to solve a problem that has not arrived.
Frequently Asked Questions
How do you measure technical debt?
Not as a balance, which cannot be measured, but as a tax. Two categories are needed together: outcome metrics such as change lead time and change failure rate, which say how heavy the penalty is, and location metrics, principally hotspot analysis multiplying change frequency by complexity, which say where it is being collected. Outcome metrics alone show slowness without a target; location metrics alone show ugly code without evidence it costs anything.
What is hotspot analysis?
A technique that ranks files or modules by change frequency multiplied by complexity, using version control history and static analysis. It matters because the interest rate on technical debt depends on how often code is touched: complex code nobody modifies costs nothing, while complex code under constant change costs continuously. Most codebases concentrate the majority of the penalty in a small number of modules, which is what makes targeted paydown practical.
Why does allocating twenty percent of time to technical debt not work?
Four structural reasons. It creates a parallel backlog that always ranks below feature work, it is the first thing cut when deadlines compress and does not come back, its value is unprovable because the counterfactual is invisible, and it does nothing to slow the rate at which new debt is created. Paydown attached to feature work in the same area survives, because the context is already loaded and the value ships with something visible.
How should technical debt be explained to a CFO?
As a recurring capacity tax with a removal price and a payback period. "Changes to this subsystem take forty percent longer and fail three times as often, it was involved in sixty percent of last quarter's work, removing the penalty costs eight engineer-weeks and returns three per quarter" is an investment case that can be compared to alternatives. Presented as code quality, it competes with features on a scale where features win.
Does AI-generated code make technical debt worse?
Both effects are real. Creation rate rises, because more code ships and generated code is often accepted with shallower understanding, and code nobody on the team understands is debt regardless of appearance. Paydown cost falls, because mechanical refactoring, test generation, documentation, and version migration are exactly what the tools do well. Which dominates depends on whether the organization routes part of the productivity gain to the hotspot list, since the default is to convert all of it into features.
The Bottom Line
The reframing that makes this tractable is abandoning the balance sheet. There is no principal, so stop asking engineering to quantify one. There is a rate, it varies enormously across a codebase, and it is only charged where code is actively changed. Everything useful follows from that: measure outcomes to size the tax, measure hotspots to locate it, and spend only where both signals agree.
The scheduling conclusion follows too. Dedicated debt time fails because it separates the work from the value, and separated work loses funding. Attaching paydown to feature work in the same subsystem makes it cheap, makes it provable, and makes it uncancellable, which are the three properties a standing allocation lacks.
The most expensive error in practice is not neglecting debt. It is paying down the wrong debt: investing serious engineering time in the module that offends most while the actual tax is levied somewhere unglamorous that nobody proposed fixing. Measurement is what separates those two, and it is cheap relative to the work it redirects.