What is Technical debt?

Engineering culture and software practice

Technical debt is a metaphor for the future cost created when software is easy enough to ship today but harder, slower, or riskier to change later. The code still works, which is why debt is tempting. The trouble appears on the next feature, the next bug fix, or the next migration, when the team spends extra time navigating awkward design, brittle tests, duplicated logic, or outdated dependencies.

What this means

Think of it as borrowing speed from the future. A team takes a shortcut, or simply builds with only a partial understanding of the problem, and gets something working sooner. That can be sensible. But later work costs more because the software no longer fits the team's current understanding or the shape of the product.

The metaphor matters because it explains something non-obvious to non-engineers. Code quality is not just aesthetics. It affects how fast a team can respond, how often changes go wrong, and how much ordinary work starts to feel like walking through wet cement.

Technical debt is also a family term. A code smell is often the first warning sign. Spaghetti code is one ugly way debt can present itself in source code. A big ball of mud is what the problem looks like at system scale. Bit rot joins in when neglected areas stop being exercised and drift out of shape.

Why it matters

If you work with engineers, technical debt helps explain why apparently simple requests can suddenly become expensive. A feature that sounds small in a planning meeting may require careful surgery if the surrounding code is fragile, confusing, or tied to old assumptions. The team is not being precious. They are paying interest.

This is why debt affects more than developer mood. It changes delivery speed, forecast confidence, incident risk, onboarding time, and staff morale. Over time, the organisation starts to feel slower without always knowing why. Work gets done, but with more caution, more rework, and more surprise.

For leaders, the term is useful because it turns a vague complaint about "messy code" into a practical trade off. Some debt is worth taking on. Some is simply neglected maintenance. The important part is to make the cost visible before it becomes the default operating model.

How it works

Where the term came from

The term was coined by Ward Cunningham in 1992 while describing how his team built the WyCash financial system by incremental growth from a working prototype. His point was not that programmers should write sloppy code and promise to tidy it later. It was that when you build iteratively, your understanding improves as you go, so earlier code often needs to be revised to reflect what you have since learned.

That is why the original metaphor has a surprisingly generous side. Debt is not always a moral failure. Sometimes it is the price of learning quickly. The problem starts when the team keeps shipping on top of code that no longer reflects what it now knows.

What the debt actually consists of

Technical debt is not one thing. It can show up as duplicated business rules, modules no one can safely change, confusing naming, brittle tests, old dependencies, hidden assumptions, temporary scripts turned permanent, or a deployment path that only one person understands. None of these items is dramatic on its own. Together, they create drag.

The interest on the debt is the extra effort added to normal work. A change that should take two days takes five. A small bug fix needs a week of checking because nobody trusts the surrounding area. A library update triggers unrelated failures. Engineers keep revisiting the same confusing code because every feature passes through it.

Paying down the principal means changing the structure, not merely surviving it. That might mean refactoring, deleting obsolete code, breaking up a large module, improving tests, replacing an old interface, or moving duplicated rules into one clear place.

Different kinds of debt

One useful way to think about debt is to ask two questions. Was it deliberate or inadvertent? And was it prudent or reckless?

Deliberate debt happens when a team knowingly chooses speed now and cost later. That can be reasonable if the trade is explicit, the gain is real, and there is a believable plan to revisit it. For example, a team may support one narrow customer workflow first, while knowing the model will need to broaden after launch.

Inadvertent debt is different. It appears because software development teaches you things while you do it. A year into a product, a team often understands the domain better than it did at the start. Even good engineers can look back and see code that made sense then but no longer matches what they know now.

Prudent debt has a bounded purpose. Reckless debt is taken on casually, or left in place after its useful life has passed. The metaphor works best when it helps a team decide which kind it is dealing with, rather than treating every rough edge as identical.

How it shows up in real work

Debt tends to gather in busy areas. The code that changes every sprint is where the interest bill arrives first. Teams feel it as growing hesitation. Engineers start warning each other before touching certain files. Pull requests get longer because people add defensive checks. New joiners need a guided tour before they can make even a modest change.

It also appears in surrounding systems. A team might have working application code but a neglected build pipeline, a fragile deployment script, or a database change process that nobody wants to touch. The product can look healthy from the outside while hidden debt makes every release more anxious than it should be.

This is one reason the term travels well beyond engineering. A business stakeholder may not care whether a class is too large, but they care if every new request needs extra ceremony. Technical debt is the business cost of internal awkwardness.

How teams pay it down in practice

Healthy teams rarely clear debt with one heroic rescue. More often, they chip away at it while doing ordinary work. They improve names while editing a function, delete dead code when they discover it, add a test before changing a brittle path, or create a seam around a messy area so later work is safer.

Sometimes larger work is needed. A migration from an obsolete API, a redesign of a pricing model, or a rework of deployment automation may need dedicated time. Even then, the best efforts usually stay narrow and purposeful. A team pays down debt fastest when it aims at a specific source of drag in an important area, not when it declares war on the entire past.

This is also where discipline matters. Debt reduction without tests can become another form of risk. Debt reduction without boundaries can become yak shaving, with the team disappearing into adjacent cleanups and emerging many days later with a prettier subsystem and a missed deadline. The point is not cleanliness for its own sake. The point is easier change.

Examples

A product starts in one country with simple tax rules. Six months later it serves several regions, each with different exemptions, rounding rules, and reporting needs. Instead of revisiting the original model, the team adds condition after condition. The software still invoices people correctly, most of the time, but every pricing change now needs careful checking in half a dozen places. That extra checking is interest.

A team promises a key customer a new export format by the end of the week. To hit the date, one engineer writes a direct translation layer in the API endpoint rather than modelling the export properly. The trade may be worth it if the file format is still uncertain and the code is revisited soon. If three more customers arrive and the quick path becomes the permanent path, the debt has started compounding.

An organisation inherits a reliable internal system that "just works" and therefore receives little love. Over the years the runtime version, libraries, deployment tooling, and naming conventions evolve around it. The next major feature looks small on paper, but nobody can extend the system safely without first modernising large chunks of it. What looked like a feature estimate problem is really debt surfacing all at once.

Common misunderstandings

Technical debt is not simply old code. Some old code is clear, stable, well understood, and cheap to change. Age alone is not the issue. Cost of change is.

Technical debt is not a synonym for bad engineers. Excellent teams still create debt because product discovery changes their understanding over time. Poor habits can make debt worse, but debt itself is not proof of incompetence.

Technical debt is not just a code problem. Tests, deployment pipelines, build tooling, data models, documentation, and ownership arrangements can all create the same future drag.

Technical debt is not something a tool can fully measure for you. Tools can spot useful clues, especially stale APIs, duplication, or other code smells. They cannot fully see when the code and the team's understanding have drifted apart.

Technical debt does not always need complete repayment. If the affected area is cold, stable, and rarely touched, partial containment may be enough. The right question is whether the debt is costing more than the work needed to reduce it.

Risks and boundaries

The term is easy to overuse. If every disliked style choice becomes technical debt, the phrase loses value. Teams then stop distinguishing between real drag, ordinary trade offs, and mere taste. That is when the metaphor becomes managerial wallpaper.

Debt can also become an alibi. "We know it is debt" is not a strategy. If nobody owns the decision, no review date exists, and no future work is shaped by the cost, then the organisation is not managing debt. It is simply living with decay.

The healthiest use of the term is precise and modest. Name the area, describe the drag, explain the cost of leaving it, and decide whether now is the moment to act.

What to do next

First, ask for specificity. Do not accept "there is lots of tech debt" as a useful statement. Ask which part of the system is slowing work, what kind of extra effort it creates, and how often the team has to pay that price.

Second, make debt visible in the same planning conversations as feature work. If a team needs to simplify a hot path before adding a major capability, treat that as part of delivery, not as side work to be squeezed in by goodwill alone.

Third, reward smaller continuous repairs. Teams that are expected to ship continuously need permission to refactor continuously. Deletions, test improvements, dependency upgrades, and interface cleanups should count as real progress because they are what keep future work from grinding down.

Finally, watch for the social signs. When engineers avoid certain files, when estimates carry a hidden fear premium, or when only one person can change a core workflow, debt is already shaping the organisation.

FAQs

Is technical debt just another name for messy code?

No. Messy code can be part of it, but the core idea is future cost. If today's design makes tomorrow's change harder, there is debt whether the code looks ugly or not.

How is technical debt different from a code smell?

A code smell is a clue. Technical debt is the broader cost picture. A smell may point to debt, but it is not the whole balance sheet.

Can a startup ignore technical debt?

A startup can accept more debt than a bank or hospital system, but it still cannot ignore it forever. Startups live on speed, and unpaid debt eventually attacks speed first.

Does technical debt mean we should rewrite everything?

Usually not. Full rewrites throw away working knowledge along with awkward structure. Most debt is better handled by targeted refactoring, deletion, and migration.

Who should own technical debt?

The team doing the work should own the local debt, with leadership making the trade offs visible and fundable. Ownership without planning is not enough, and planning without ownership is theatre.

How do you explain technical debt to non-engineers?

Describe the interest. Say what takes longer, what fails more often, or what requires rare expertise. Once the drag is visible, the metaphor tends to make sense very quickly.

Sources