Skip to content
EngineeringAll explainers

Technical debt: what it is, what it costs, and when to repay

Technical debt is the future cost of a shortcut taken now, paid later as slower changes. Where the metaphor comes from, Fowler's quadrant for telling prudent shortcuts from reckless ones, the symptoms that show up before anyone names the cause, and what's worth repaying first.

On this page

Technical debt is the future cost of choosing a faster solution today over a better one: the difference between them doesn't disappear, it sits in the codebase and gets paid later, as changes that take longer than they should. A team ships the quick version to hit a date, and every feature built on top of it inherits the gap, until someone deals with it directly or routes around it for good.

Where the metaphor comes from

The metaphor traces to Ward Cunningham, who introduced it in a 1992 OOPSLA experience report describing his team's work on a portfolio management system called WyCash. Cunningham used it to explain to non-technical stakeholders why shipping a first, imperfect implementation and reworking it later made sense, the way a loan lets you act now and settle the difference once you understand the problem properly. The framing caught on because borrowing against future speed is intuitive. It breaks down at the loan part. A bank loan has an agreed amount, an interest rate, and a due date, settled before anyone spends the money. Most technical debt has none of that agreed in advance; it gets discovered later, in code, rather than chosen out loud.

Deliberate versus inadvertent

Not all technical debt is the same type. Martin Fowler's quadrant sorts it along two axes: deliberate versus inadvertent, whether the team chose the shortcut on purpose or backed into it without realizing, and prudent versus reckless, whether anyone weighed what the shortcut would cost. Deliberate, prudent debt is a legitimate tool: a startup skips a permissions system it doesn't need yet to ship a pilot, knowing exactly what got left out and why. Reckless debt is the kind where that weighing never happened, whether the team decided there was no time for design or never knew a better structure existed. Going unrecorded is what compounds it. A shortcut written down stays visible enough to prioritize later; one nobody noted just looks like normal code, until a change built on top of it breaks for reasons nobody can trace back.

How the interest shows up

The interest shows up as friction long before anyone calls it debt. An estimate that used to take three days stretches to two weeks, for a feature no more complicated than the last one. A single business rule gets copy-pasted into a dozen places instead of centralized once, so a pricing change means editing all twelve, and someone always misses one. New engineers take months to get productive, not because the stack is unfamiliar, but because the code doesn't behave the way its structure suggests. Each symptom looks small alone; a team adjusts its expectations gradually enough that the slowdown never gets named. The scale adds up industry-wide: the Consortium for Information and Software Quality estimated accumulated US technical debt at $1.52 trillion in its 2022 report, tracked separately from the cost of bugs and outages.

Deciding what debt to repay

Repay debt in code the team is already touching, and leave stable code alone. Technical debt management rarely gets more complicated than that. A shortcut in a feature nobody has changed in two years isn't costing anyone anything right now, however rough it looks, so it can wait. A shortcut sitting in the integration layer between two services, or in whatever file gets edited every sprint, is worth clearing quickly, since every future visit gets a little easier once it's gone. The practical rule: pair repayment with a change already planned, rather than opening a file purely to tidy it. That keeps the fix small, reviewable, and tied to something the business asked for, instead of a separate initiative that has to justify its own existence first.

How repayment goes wrong

Repayment fails less often because of the debt itself than because of how a team chooses to pay it down.

  • A refactoring sprint with no product outcome attached. Blocking off two weeks for cleanup nobody outside engineering can see makes it the first thing cut when a deadline slips, usually cancelled halfway, leaving two competing patterns instead of one finished version.
  • Reaching for a rewrite instead of paying debt down in pieces. A rewrite freezes feature work and assumes the team can safely leave out every old shortcut this time, which is rarely true. The new codebase often grows its own debt before the old one retires.
  • Measuring debt with a tooling score nobody acts on. A static analyzer reports a maintainability number, someone glances at it monthly, and no ticket ever gets filed against it. The score becomes something to report, not something to fix.
  • Calling every shortcut debt. Once the word covers any code someone dislikes, it stops helping anyone decide what to fix first. A label that means everything ranks nothing.

Bringing in help to pay it down

Delivery speed has visibly halved and nobody inside agrees on why. A team inside the code daily loses the distance to tell a shortcut that genuinely slows every change from one that is merely ugly, so the argument runs on opinion until an outside read settles it. The harder version is a codebase whose authors have all left: nothing in the code says whether a shortcut was prudent under a deadline or reckless from the start, and that difference decides whether it gets repaid or replaced. Debt that far along sits closer to legacy modernization than to ordinary cleanup.

Software development consulting is the usual starting point for that assessment; product development and custom software development carry out the repayment once priorities are clear.

Frequently asked questions

  • No. A shortcut taken on purpose, with its cost weighed and written down somewhere findable, is a normal tradeoff rather than a failure. The damaging kind is the shortcut whose cost nobody weighed at all, and going unrecorded on top of that keeps anyone from revisiting it.

  • A bug is broken behavior the code was never meant to have. Technical debt is a working decision, made under time pressure, whose cost shows up later as slower changes rather than incorrect output. A system can ship with zero open bugs and still carry enough debt to make the next six months harder than they need to be.

  • Not in a way that transfers. Static analyzers can estimate remediation effort in hours or count code smells, and that figure is useful as a trend inside one codebase watched over months. It carries almost nothing across teams, because the same tool run against two systems mostly reflects their language, age, and rule configuration rather than the debt either one actually carries. No industry standard exists to normalize it, so a score copied from someone else's dashboard is not a benchmark.

  • Not in the sense of reaching zero. New debt gets created every time a team ships something under a deadline, which is most of the time, so the realistic goal is keeping the debt that's actively slowing the team down smaller than the team's capacity to address it, not eliminating debt altogether. A codebase with zero debt more often means nobody's shipping anything than that the team is unusually disciplined.