What Is Technical Debt?
Technical debt is the implied future cost of rework created when a team chooses an easier solution now over a better one that would take longer. Like financial debt it carries interest — every future change to the affected code costs more — and that interest compounds until the debt is paid down.
Every working system carries some debt. The codebase that ships features this quarter was shaped by a hundred reasonable compromises — the shortcut taken to hit a launch, the library adopted before anyone knew it would calcify, the design that fit the problem in 2014 and has been stretched ever since. None of those decisions was wrong on the day it was made. Their cost arrives later, quietly, as a tax on everything that comes after. That tax is technical debt, and this series is about measuring it, pricing it, and paying it down without halting delivery.
This first part defines the term precisely, because most arguments about technical debt are really arguments about what the words mean.
The original metaphor — and why it still holds
The phrase comes from Ward Cunningham, who in 1992 described shipping code that is not quite right as taking on a debt. A little debt speeds development, he argued, so long as it is paid back promptly with a rewrite. The danger was never the borrowing — it was leaving the debt unpaid, because every minute spent on not-quite-right code counts as interest on that debt.
The metaphor has survived three decades because the financial analogy is exact in the ways that matter. You borrow when you choose the faster, cheaper solution over the better one. The principal is the work it would take to do it right. The interest is the extra effort every future change incurs because you didn’t. And, like real debt, the interest compounds: debt in one part of the system makes the next shortcut more tempting and the next change more expensive, until a large fraction of the team’s capacity goes to servicing debt rather than building.
Cunningham’s own caveat is the part most often forgotten. He was not warning teams off shortcuts. He was describing a tool — leverage — that works only if you intend to repay. Debt you take on knowingly and repay promptly is a sound investment. Debt you take on unknowingly and never record is the kind that sinks systems.
A working definition
Technical debt is the implied future cost of rework caused by choosing an expedient solution now over a better one that would have taken longer. Three words in that sentence carry the weight.
Implied — the cost is real but not yet on any invoice. It shows up later as slower delivery, more defects, and higher maintenance, rarely as a line item anyone tracks.
Future — debt is about the cost of change, not the cost of running. A system can run perfectly and still be expensive to modify. The interest is paid by the next person who has to touch the code.
Rework — the debt is the gap between what exists and what would let the system change cheaply. Closing that gap is the principal repayment.
This is why “technical debt” and “bad code” are not synonyms. Code can be ugly and cheap to change, or elegant and ruinously expensive to change. Debt is measured by what it costs you to evolve the system — not by how the code reads.
Debt is not a defect
The most common confusion is between debt and bugs. A bug is behavior that is wrong now. Debt is structure that makes future change expensive even when behavior is correct. The distinction is not academic, because it changes who should care and when.
A bug interrupts a user today, so it gets a ticket and a fix. Debt interrupts a developer next quarter, so it gets nothing — there is no user complaining, no alert firing, no obvious moment to act. That asymmetry is exactly why debt accumulates: the system that works is the system nobody is funded to improve. A codebase can pass every test, satisfy every requirement, and still be so tangled that a one-day feature takes two weeks. That two-week feature is the interest payment, and no bug tracker will ever show it to you.
The interest is the whole problem
If technical debt only cost you the principal — the one-time price of doing it right — it would be a rounding error. The reason it dominates engineering economics is the interest, and the interest is paid continuously by everyone who touches the affected area.
Consider a module with no tests and tangled dependencies. Every change to it requires manually re-checking behavior the tests should have guaranteed, tracing dependencies the structure should have made obvious, and fixing the things that break elsewhere because the coupling was never cleaned up. None of that effort produces new value. It is pure interest — the recurring cost of having borrowed against the code’s future. The more the team changes that module, the more interest it pays; the area of highest debt is usually the area of highest activity, which is the worst possible combination.
This is the mechanism behind a figure worth holding onto: Stripe’s 2018 report “The Developer Coefficient” found that developers lose roughly 42% of their time to technical debt and bad code. Read that as an interest rate. Nearly half of paid engineering capacity, across the firms Stripe surveyed, goes to servicing the debt rather than building against it. The principal was borrowed long ago; the interest is being paid every single sprint.
How the interest compounds
Debt does not stay still. It compounds, through three mechanisms that reinforce one another.
The broken-windows effect. A shortcut in a clean system stands out and gets fixed. The same shortcut in a system already full of shortcuts is invisible — it matches the surroundings. Disorder lowers the bar for the next person, so debt begets debt.
Coupling spreads cost. Debt concentrated in one module would be containable if the module were isolated. It rarely is. Tightly coupled code means a problem in one place raises the cost of changes everywhere it reaches, and the reach grows as the system grows.
Knowledge decays. The reasons behind the original shortcuts live in people’s heads, and people leave. Each departure converts documented-in-someone’s-memory debt into archaeological debt — the kind where no one alive knows why the code does what it does, only that touching it is dangerous. We treat that knowledge loss as its own cause in Part 3, because it is one of the largest and least-tracked sources of debt there is.
Compounding is why a system that was “a little messy” five years ago is “too risky to touch” today. Nothing dramatic happened. The interest simply kept accruing.
When taking on debt is the right call
Honesty requires naming the other side: deliberate debt is often the correct decision, and a team that refuses all debt is as mismanaged as one that ignores it.
Borrowing to ship makes sense when speed has real value and the debt is recorded. Testing whether a market exists before investing in a system that scales. Hitting a regulatory deadline that does not move. Getting a feature in front of real users to learn what to build properly. In each case the right move is to take the shortcut on purpose, write down what you borrowed and why, and schedule the repayment. That is leverage used well.
The failure is not the borrowing. It is borrowing unknowingly, never recording the debt, and never repaying it — so the interest compounds in the dark until it dominates the cost of every change. Most of the debt that cripples a system was never a decision at all. It accumulated.
Debt versus legacy
It is worth drawing the line between technical debt and a legacy system, because they are related but not identical. Debt is the accumulating cost of change inside a system. A legacy system is what you have when that debt has compounded for years past the point where anyone can confidently or affordably change it — aging dependencies, departed knowledge, and structure that resists every modification at once. Technical debt is the mechanism; a legacy system is the destination if the debt is never managed. The signs your system has become legacy are, in large part, the symptoms of debt left to compound.
Not everything is debt
Not all friction is debt, and calling everything “tech debt” is its own failure mode. A feature that is genuinely hard because the problem is genuinely hard is not debt. A system that is slow to change because it is large and does a great deal is not necessarily in debt — it may simply be big. And the label is sometimes used to relitigate decisions an engineer disagrees with on taste alone. Debt is specifically the avoidable future cost created by an expedient past choice. Friction that no better choice would have removed is just the cost of the work. Keeping that line sharp is what lets you measure debt honestly rather than use it as a catch-all for everything unpleasant about a codebase.
Where this leads
We now have a definition: technical debt is the compounding future cost of rework, distinct from bugs, distinct from legacy, and not always bad. But “technical debt” as a single term is too coarse to act on, because the debt that lives in your code is paid down very differently from the debt that lives in your architecture or your aging dependencies. Part 2, Types of Technical Debt, breaks the term into the distinct kinds of debt a real system carries — and explains why naming the type is the first step toward pricing it.
Frequently asked questions
- Is technical debt always bad?
- No. Deliberately taking on debt to ship sooner — to test a market, hit a deadline, or learn from real users — can be the right call, exactly as borrowing money can be. Debt becomes a problem when it is taken on unknowingly, never recorded, and never repaid, so the interest compounds silently until it dominates the cost of every change.
- What is the difference between technical debt and a bug?
- A bug is behavior that is wrong now; technical debt is structure that makes future change expensive even when the system works correctly today. A system can be entirely bug-free and still be deep in debt — and that debt is what turns a one-day feature into a two-week one. Debt is a property of the code and architecture, not of the output.
- Who is responsible for technical debt?
- Both engineering and the business own it. Engineers create it through shortcuts and aging dependencies; the business creates it through deadline pressure, deferred upgrades, and roadmaps that never fund repayment. Treating debt as purely an engineering hygiene issue is why it goes unpriced and unpaid — it is a business liability that happens to be denominated in code.