Skip to content

Technical Debt

Technical debt is the accumulated cost of past decisions that make future work harder. Like financial debt, it's not inherently bad—sometimes taking on debt is the right choice. But unmanaged debt compounds, eventually consuming so much of your capacity that you can barely move.

This page provides a framework for making technical debt visible, prioritizing it rationally, and paying it down sustainably alongside feature work.

What Problem This Solves

Every codebase has technical debt. The problem is not that debt exists—it's that debt is invisible, unmanaged, and politically contested.

When debt is invisible, engineers experience friction without being able to name it or quantify it. "Everything takes forever" but nobody knows why.

When debt is unmanaged, it grows until it dominates. Small issues become big ones. Workarounds become permanent. Eventually, even simple changes require extensive archaeology.

When debt is contested, addressing it becomes a political fight between engineers who feel the pain and stakeholders who don't see the value. Technical work competes unfairly with features because it lacks visible user impact.

A good debt management system makes debt visible, quantifiable, and part of normal planning—not an exception that requires special negotiation.


When to Focus on Debt

Actively address debt when:

  • Velocity is declining despite stable team size
  • Frequent bugs in specific areas of the codebase
  • Engineers consistently report friction in certain areas
  • Onboarding new engineers is unusually hard
  • Changing one thing breaks unexpected other things
  • You're planning major changes to an area with known debt

Maintain debt hygiene when:

  • Things are working well but you want to keep them that way
  • Ongoing work intersects with existing debt (the "boy scout rule")
  • You're between major initiatives and have capacity

Defer debt when:

  • You're in true crisis mode and survival is the priority
  • The area is about to be replaced or deprecated anyway
  • The debt is painful but not blocking anything important

Ownership

Role Responsibility
Tech Lead Maintains debt inventory, proposes debt work, makes technical decisions about approach
Engineering Manager Ensures debt gets budgeted time, facilitates prioritization with stakeholders
Product Manager Understands debt impact on velocity and quality, partners on prioritization
Individual Contributors Identifies and documents debt, addresses debt opportunistically

Debt is a team responsibility

Don't create a "debt czar" who owns all debt. Everyone should identify debt and contribute to addressing it. The Tech Lead curates and prioritizes, but doesn't own execution alone.


Taxonomy of Technical Debt

Not all debt is the same. Understanding the type of debt helps you prioritize and communicate.

By Origin

Deliberate debt: Taken on consciously for good reasons (e.g., shipping a quick solution to meet a deadline, with a plan to improve later). This is healthy if managed.

Accidental debt: Accumulated through accumulated small decisions, lack of standards, or knowledge gaps. Nobody decided to create this debt; it emerged.

Bit rot: Debt that grew because the world changed. Dependencies got outdated. The system wasn't maintained. What was fine three years ago is now a problem.

By Impact

Velocity debt: Makes development slower. Every change takes longer. Simple things are hard. Examples: poor abstractions, missing tests, confusing code structure.

Stability debt: Makes the system less reliable. Bugs, outages, and edge cases. Examples: missing error handling, race conditions, inadequate monitoring.

Security debt: Creates security vulnerabilities. Examples: outdated dependencies with known CVEs, improper input validation, weak authentication.

Scalability debt: Limits the system's ability to grow. Examples: inefficient queries, monolithic architecture that can't scale independently, hardcoded limits.

By Scope

Local debt: Contained to a specific area. Fixing it doesn't require coordinating across teams or systems.

Systemic debt: Affects multiple areas. Fixing it requires coordination, migration, or broad changes.


Making Debt Visible

You can't manage what you can't see. Making debt visible is the first step.

Debt Inventory

Maintain a list of known technical debt. This doesn't need to be comprehensive—it needs to capture the significant items that affect your team.

For each debt item, capture:

  • What: Description of the debt
  • Where: Which systems/files/areas are affected
  • Impact: How it affects velocity, stability, security, or scalability
  • Cost to fix: Rough estimate (S/M/L or time)
  • Cost of not fixing: What happens if we leave it

Debt Discovery

Systematic sources:

  • Retrospectives: "What slowed us down?"
  • Incident postmortems: Root causes often point to debt
  • Code review: Patterns of "this is a workaround because..."
  • Dependency audits: Outdated packages, security vulnerabilities
  • Architecture reviews: Scaling limits, coupling issues

Opportunistic sources:

  • Engineers encounter friction during regular work
  • Onboarding new engineers reveals pain points
  • Debugging sessions expose hidden complexity

Debt Metrics

Quantify debt where possible:

  • Cycle time by area: Is one area consistently slower to change?
  • Bug density by area: Are certain areas more error-prone?
  • Dependency age: How outdated are your dependencies?
  • Test coverage gaps: Are critical areas untested?
  • Build/deploy time: Is CI/CD getting slower?

Prioritizing Debt

You can't fix all debt at once. Prioritization is how you ensure you're working on the debt that matters most.

The Impact/Effort Matrix

Low Effort High Effort
High Impact Do first Plan carefully
Low Impact Do opportunistically Probably don't do

High impact, low effort: These are the quick wins. Fixing them removes significant friction for modest investment. Do these whenever you have capacity.

High impact, high effort: These are strategic investments. They need to be planned, sliced, and resourced. Don't tackle them without commitment.

Low impact, low effort: Fix these when you're already working in the area ("boy scout rule"). Don't prioritize them specifically.

Low impact, high effort: These are traps. They feel important but don't actually help. Say no unless something changes.

Prioritization Factors

Pain frequency: How often does this debt hurt? Daily friction is worse than annual friction.

Blast radius: How many people/systems are affected? Widespread pain justifies higher priority.

Risk: Does this debt create reliability or security risk? Risk-reducing work often gets undervalued.

Opportunity: Is there upcoming work that will be significantly easier if we address this debt first?

Dependency: Does other work depend on addressing this debt?


The Debt Budget

The most sustainable approach to debt is to budget time for it consistently, rather than negotiating for it case by case.

Allocation Models

Percentage allocation: Reserve 10-20% of capacity for technical work (debt, infrastructure, tooling). This provides consistent investment without negotiation overhead.

Rotation: Dedicate one engineer per sprint to tech debt (rotating). This ensures focus without consuming the whole team.

Slack time: Leave buffer in sprint planning that can be used for debt or will naturally get used for it.

Dedicated sprints: Every N sprints, run a "tech debt sprint." This provides focus but can create boom/bust cycles.

Making the Budget Real

Track it: Measure how much capacity actually goes to debt vs. planned.

Protect it: The debt budget shouldn't be the first thing cut when deadlines are tight.

Communicate it: Stakeholders should know the debt budget exists and why.

Show value: When debt work improves velocity or stability, make it visible.


Executing Debt Work

The Boy Scout Rule

"Leave the code better than you found it." When working in an area with debt, address what you can without significantly expanding scope. This provides continuous improvement without dedicated debt sprints.

What this looks like:

  • Refactoring a confusing function you had to understand anyway
  • Adding tests for code you had to change
  • Updating a dependency in an area you're modifying
  • Improving documentation as you figure things out

Slicing Debt Work

Large debt items should be sliced just like features. Don't plan "refactor the payments system" as a single item. Break it into increments that can be delivered and merged independently.

Slicing strategies:

  • By risk: Address the highest-risk areas first
  • By dependency: Start with the pieces that unblock other work
  • By vertical slice: Improve one user journey end-to-end
  • Strangler fig: Build the new system alongside the old, migrate incrementally

Avoiding the Big Rewrite

The big rewrite is almost always a mistake. It takes longer than estimated, introduces new bugs, and often never ships.

Instead:

  • Improve incrementally
  • Replace components one at a time
  • Use the strangler fig pattern
  • Accept "good enough" when perfection would take forever

If you must do a large refactor, slice it aggressively and ship increments continuously.


What Good Looks Like

You'll know debt management is working when:

Signal What it looks like
Debt is visible There's an inventory; everyone knows what the significant debt is
Debt is budgeted Time for debt work is planned, not fought for
Debt is declining The inventory shrinks over time; severe items get addressed
Velocity is stable Development speed isn't degrading despite growing scope
Engineers feel heard Technical concerns are taken seriously, not dismissed
Stakeholders understand Product/leadership know the debt situation and why it matters

Anti-patterns

All debt, no features: If you're only working on debt, something is wrong. Debt work should enable feature delivery, not replace it.

No debt budget: If debt only gets addressed when engineers push back hard, you have a negotiation problem.

Debt theater: If debt is "addressed" by renaming or reorganizing the backlog without actually fixing things, you have a culture problem.


Failure Modes and Mitigations

The Debt Denial

Symptom: Leadership doesn't believe debt is real or significant. Engineers are told to "just ship."

Root cause: Debt is invisible. Impact isn't quantified. The connection between debt and velocity isn't made.

Mitigation: Make debt visible with data. Show the cycle time difference between clean and debt-heavy areas. Track bugs by area. Quantify the cost of not fixing.

The Debt Spiral

Symptom: Debt grows faster than you can pay it down. Every sprint creates more debt than it resolves.

Root cause: No systematic investment. Debt only addressed in crisis. New work creates debt faster than old debt is resolved.

Mitigation: Establish a real debt budget. Enforce code quality standards to slow debt creation. Be willing to say "no" to features that create unacceptable debt.

The Big Rewrite Trap

Symptom: The team decides to "rewrite everything" to escape debt. The rewrite takes 2x longer than expected, ships with its own bugs, and never fully replaces the old system.

Root cause: Underestimating the complexity of the current system. Overestimating the cleanliness of the rewrite. Not slicing incrementally.

Mitigation: Slice ruthlessly. Ship increments. Use strangler fig patterns. Accept that "good enough" is the goal, not perfection.

The Debt Politics

Symptom: Debt work becomes a fight between engineering and product. Engineers feel unheard. Product feels blocked.

Root cause: Debt is framed as technical preference vs. business value. No shared language or prioritization framework.

Mitigation: Frame debt in terms of business impact (velocity, reliability, risk). Use shared prioritization criteria. Establish the debt budget as a non-negotiable investment.


Copy-Paste Artifact: Debt Item Template

## Technical Debt Item: [Title]

**ID:** DEBT-[number]
**Created:** [Date]
**Author:** [Name]

### Description

[What is the debt? What's wrong with the current state?]

### Location

[Which systems, services, files, or areas are affected?]

### Impact

**Type:** [ ] Velocity [ ] Stability [ ] Security [ ] Scalability

**Description of impact:**
[How does this debt affect the team/system? Be specific.]

**Pain frequency:** [ ] Daily [ ] Weekly [ ] Monthly [ ] Rarely

**Blast radius:** [ ] Team [ ] Multiple teams [ ] Organization [ ] Customers

### Effort

**Size estimate:** [ ] Small (< 1 day) [ ] Medium (1-5 days) [ ] Large (1-2 weeks) [ ] XL (> 2 weeks)

**Complexity:** [ ] Low [ ] Medium [ ] High

**Risk:** [ ] Low [ ] Medium [ ] High

### Proposal

**Proposed solution:**
[How would we address this debt?]

**Acceptance criteria:**
[How do we know the debt is resolved?]

### Prioritization

**Cost of delay:** [What happens if we leave this for 6 more months?]

**Dependencies:** [Does other work depend on this? Does this depend on other work?]

**Recommendation:** [ ] Do now [ ] Plan next quarter [ ] Opportunistic [ ] Defer

---

**Status:** [ ] Open [ ] In Progress [ ] Done [ ] Won't Do
**Resolution:** [If resolved, what was done? If won't do, why?]

Copy-Paste Artifact: Quarterly Debt Review Agenda

## Quarterly Technical Debt Review

**Date:** [Date]
**Attendees:** [Tech Lead, EM, PM, senior engineers]
**Duration:** 60-90 minutes

### Objectives

- Review current debt inventory
- Assess debt trends
- Prioritize debt for next quarter
- Agree on debt budget

### Agenda

**1. Debt Inventory Review (20 min)**

- Walk through current debt inventory
- Add new items identified this quarter
- Remove resolved or no-longer-relevant items
- Current count by type: Velocity **_ | Stability _** | Security **_ | Scalability _**

**2. Trend Assessment (15 min)**

- Is debt growing or shrinking overall?
- Which areas are improving? Which are getting worse?
- What metrics indicate debt impact? (cycle time, bug density, etc.)

**3. Prioritization (25 min)**

- Review high-impact items
- Apply impact/effort matrix
- Identify top 3-5 items for next quarter
- Identify opportunistic items for boy scout work

**4. Budget and Commitment (15 min)**

- Confirm debt budget for next quarter (target: \_\_% of capacity)
- Assign owners for priority items
- Agree on tracking and review cadence

### Output

- [ ] Debt inventory updated
- [ ] Top priority items identified and owned
- [ ] Debt budget confirmed
- [ ] Next review scheduled

### Priority Items for Q[X]

| Item    | Owner  | Target        | Size    |
| ------- | ------ | ------------- | ------- |
| [Title] | [Name] | [Date/Sprint] | [S/M/L] |

Copy-Paste Artifact: Debt Budget Tracker

## Debt Budget Tracker

**Quarter:** [Q_ YYYY]
**Team:** [Name]
**Planned debt budget:** [__%] of capacity

### Sprint-by-Sprint

| Sprint            | Total points | Debt points | Debt %  | Notes |
| ----------------- | ------------ | ----------- | ------- | ----- |
| Sprint 1          | \_\_\_       | \_\_\_      | \_\_\_% |       |
| Sprint 2          | \_\_\_       | \_\_\_      | \_\_\_% |       |
| Sprint 3          | \_\_\_       | \_\_\_      | \_\_\_% |       |
| ...               |              |             |         |       |
| **Quarter Total** | \_\_\_       | \_\_\_      | \_\_\_% |       |

### Debt Items Completed

| Item    | Size    | Impact           |
| ------- | ------- | ---------------- |
| [Title] | [S/M/L] | [What improved?] |

### Assessment

**Did we hit the budget target?** [ ] Yes [ ] Close [ ] No

**If no, why?**
[What happened? Was it a prioritization issue, estimation issue, or external factor?]

**Impact of debt work:**
[What improved because of debt work? Can we quantify velocity or stability gains?]

**Adjustment for next quarter:**
[Should we change the budget? The approach? The priority items?]

Further Reading

  • Working Effectively with Legacy Code by Michael Feathers – Techniques for improving code you inherit
  • Refactoring by Martin Fowler – The discipline of improving code without changing behavior
  • The Pragmatic Programmer by David Thomas and Andrew Hunt – Includes discussion of software entropy