Direct answer
Technical debt is the implied cost of extra rework caused by choosing an easy or fast solution now instead of a better one that would take longer. Like a financial loan, it has a principal (the shortcut itself) and interest (the ongoing extra cost of building on top of it until it is paid down). It shows up in several distinct categories, and treating them as one blob is itself a common mistake.
Structured elaboration
The categories worth tracking separately, because they accumulate differently and need different owners:
| Category | What it looks like | Typical accumulation path | A signal to collect |
|---|
| Code debt | Duplicated logic, tangled functions, inconsistent style | Rushed features, copy-paste under deadline | Cyclomatic complexity, duplication percentage |
| Design/architecture debt | Wrong module boundaries, a component doing too much | Requirements drift past the original design | Cross-module dependency count, change-amplification (how many files a typical PR touches) |
| Test debt | Missing or shallow tests, brittle end-to-end suites | Skipping tests to hit a date | Test coverage delta, flaky-test rate |
| Infrastructure/build debt | Slow builds, manual deploys, outdated CI | Infra work deprioritized versus features | Build time trend, deploy frequency |
| Documentation/knowledge debt | Undocumented decisions, tribal knowledge | Single-owner components, high turnover | Time-to-first-PR for new hires, bus-factor per component |
Two of the signals above use terms worth defining plainly: cyclomatic complexity (roughly, how many independent decision paths run through a function; more branches and loops means a higher number) and bus-factor (how many people could leave the team before no one is left who understands this component). Each category needs its own signal because a healthy test-coverage number can coexist with severe architecture debt, and vice versa; a single composite "debt score" without category breakdown hides which lever to pull.
Worked example
A payments service might show: code debt (a 400-line processOrder function mixing validation, pricing, and persistence), design debt (the pricing logic is duplicated in the checkout service because there was no shared module), test debt (checkout has 40% coverage while the rest of the codebase averages 75%), and documentation debt (the only engineer who understands the tax-calculation edge cases left the company eight months ago). Four different categories, four different remediation owners and timelines, even though a single dashboard might report "technical debt: high" for the whole service.
Trade-offs & pitfalls
The most common mistake is treating debt as inherently bad. Deliberately taking on debt to hit a real deadline, with a plan to repay it, is a normal engineering trade-off, not a failure. The pitfall is debt taken on silently, with no tracking and no repayment plan, which is what actually causes long-term damage. A second pitfall is conflating technical debt with a bug: a bug is a defect against the current spec, while debt is a legitimate design choice that becomes more expensive to live with over time.