Every engineering team carries technical debt, whether they acknowledge it or not. It accumulates in shortcuts taken during a sprint crunch, in libraries nobody updated, in the authentication module that only one person understands. According to a 2024 Stripe study, developers spend 17 hours per week on maintenance and understanding toil, much of it rooted in unmanaged technical debt. This guide breaks down what technical debt actually is, how to measure it, and how to build a sustainable plan for paying it down without grinding feature work to a halt.
We wrote this because at Glue, we watch teams struggle with the same pattern: debt builds silently, velocity drops gradually, and by the time leadership notices, the cost of fixing things has tripled. Understanding the problem is the first step toward solving it.
What Is Technical Debt
Ward Cunningham coined the term "technical debt" in 1992 to describe the implied cost of choosing a faster, less thorough implementation today that will require rework later. Think of it like financial debt: you borrow speed now and pay interest in the form of slower development, more bugs, and harder onboarding.
But the analogy only stretches so far. Financial debt is deliberate and tracked. Technical debt often accumulates without anyone noticing. A quick fix ships on Friday. A workaround becomes permanent. A dependency falls three major versions behind. None of these appear on a balance sheet, but they all slow your team down.
Technical debt is not inherently bad. Shipping a minimum viable feature with known shortcuts is a legitimate strategy when you plan to revisit it. The trouble starts when nobody tracks what was deferred, nobody owns the cleanup, and the "temporary" solution survives for three years.
At its core, technical debt represents the delta between how your code is and how it should be to support the pace and reliability your team needs. When that delta grows too large, everything from sprint planning to hiring gets harder.
The concept has become more important as codebases grow faster. With AI-assisted coding tools generating code at higher volume, teams are building more, but the cost of understanding what already exists is growing in lockstep. A codebase that doubles in size does not just double its maintenance burden. It roughly squares the number of potential interactions between components. That combinatorial growth is why technical debt becomes crippling faster than teams expect.
The Technical Debt Quadrant
Martin Fowler's technical debt quadrant offers a useful framework for categorizing the debt your team carries. It plots debt along two axes: deliberate vs. inadvertent and prudent vs. reckless.
Deliberate and Prudent: "We know this module needs a better abstraction, but shipping now and refactoring next sprint is the right tradeoff." This is strategic debt. The team understands the cost and plans to pay it back.
Deliberate and Reckless: "We don't have time for tests, just ship it." This is the most dangerous category because the team knowingly skips quality without a repayment plan.
Inadvertent and Prudent: "Now that we've built the feature, we realize there was a better design." This is the debt of learning. It happens in every growing codebase and reflects natural evolution.
Inadvertent and Reckless: "What's a layered architecture?" This comes from inexperience or missing code review practices. It tends to accumulate in corners of the codebase nobody reviews carefully.
The quadrant matters because not all debt deserves the same response. Prudent deliberate debt might be fine to carry for a quarter. Reckless inadvertent debt should trigger a conversation about mentoring and review processes.
A 2023 study published in IEEE Software found that teams who categorized their debt using a framework like this paid it down 40% faster than teams who treated all debt as a single backlog item. Categorization forces prioritization, and prioritization makes action possible.
When you discuss technical debt with your team, start by identifying which quadrant each item falls into. A shared language for talking about debt reduces the emotional charge ("we wrote bad code") and replaces it with a productive framing ("we made a deliberate tradeoff and now the interest rate is rising"). Teams that categorize their debt consistently report better conversations during sprint planning because the debate shifts from "should we fix this?" to "what type of debt is this, and what is the right timeline for addressing it?"
The quadrant also helps engineering leaders communicate with non-technical stakeholders. "We deliberately took on some implementation shortcuts to hit our Q3 launch date, and now we need to invest in Q1 to pay that down" is a story that business leaders understand because it mirrors financial decisions they make every quarter.
Types of Technical Debt
Technical debt shows up in several distinct forms. Treating them as one thing leads to vague backlogs that never get prioritized.
Code Debt
The most visible form. Duplicated logic, deeply nested conditionals, functions that do too many things, naming that confuses instead of clarifying. Code debt raises the cost of every change that touches the affected area. If you have ever searched for the term code smell, you were looking at code debt symptoms.
Architecture Debt
The system was designed for 10 users and now serves 10,000. A monolith that should have been decomposed. A synchronous workflow that should be event-driven. Architecture debt is expensive to fix because it requires coordinated changes across multiple services and teams.
Test Debt
Missing tests, flaky tests, tests that pass regardless of what the code does. Test debt compounds silently: every untested path is a potential production incident waiting for the wrong input. Teams with low test coverage spend 2-3x more time on regression testing during releases.
Documentation Debt
Outdated README files. API docs that reference deprecated endpoints. Onboarding guides that describe a codebase from two years ago. Documentation debt directly increases the time new engineers need to become productive.
When nobody knows how the system works, every task takes longer because each developer must rediscover context that should have been captured.
Dependency Debt
Third-party libraries that are multiple major versions behind. Deprecated packages still in production. Security vulnerabilities in transitive dependencies. Dependency debt often stays invisible until a CVE forces an emergency upgrade.
Infrastructure Debt
Manual deployment steps. Missing monitoring. Environments that drift from production. Infrastructure debt slows delivery and increases the blast radius of incidents.
Process Debt
The team outgrew its workflows but never updated them. Code reviews that take three days. Release processes that require a specific person. Process debt is not in the code, but it taxes velocity just the same.
Design Debt
The data model made sense when the product had three user types and two workflows. Now it has twelve user types and thirty workflows, but the original schema has not changed. Design debt manifests as increasingly complex business logic that compensates for a model that no longer fits reality. It is often the most expensive form of debt to address because it touches every layer of the application.
Understanding the specific type of debt you are dealing with changes how you respond. Code debt might take a focused week. Architecture debt might take a quarter. Recognizing the difference before you start prevents underestimation and scope surprise.
How to Measure Technical Debt
You cannot manage what you cannot measure, but measuring technical debt is notoriously difficult. There is no single number that captures the full picture. Instead, effective measurement combines several signals.
The Technical Debt Ratio
The technical debt ratio (TDR) compares the cost of fixing existing debt to the cost of building the system from scratch. A common formula:
TDR = (Remediation Cost / Development Cost) x 100
A TDR under 5% is generally considered manageable. Between 5-10% signals growing risk. Above 10% means debt is actively slowing delivery. Use a technical debt calculator to estimate your team's current ratio.
Code-Level Metrics
- Cyclomatic complexity: How many independent paths exist through a function. Higher numbers mean harder testing and higher bug risk.
- Code duplication: Percentage of duplicated blocks. More duplication means more places to update when logic changes.
- Code churn: Files modified most frequently. High-churn files are often the most fragile parts of your system.
- Coupling: How interdependent your modules are. Tight coupling means changes ripple unpredictably.
Velocity Indicators
- Cycle time trending upward: If the same type of task takes progressively longer, debt is likely the cause.
- Bug rate per feature area: Concentrated bugs signal concentrated debt.
- Onboarding time: If new engineers take longer to become productive than they used to, undocumented complexity is growing.
Developer Surveys
Ask your team where they feel the most friction. Developer experience surveys consistently surface the highest-impact debt because the people writing code feel the drag daily. According to the 2024 Stack Overflow Developer Survey, developers rank "working with existing code" as their top productivity blocker, ahead of meetings, unclear requirements, and tooling problems.
Time-Based Tracking
Track the age of known technical debt items. An item that has been on the backlog for six months without being addressed is either not important enough to fix (in which case, close it) or too difficult to prioritize (in which case, reframe it in terms of business impact). Stale debt backlogs create noise that makes it harder to identify the items that genuinely matter.
Some teams use a "freshness date" approach: every technical debt item gets a review date. If it has not been addressed or reprioritized by that date, the team must decide whether to schedule it, escalate it, or close it. This prevents the backlog from becoming a graveyard of good intentions.
Prioritizing Debt Repayment
Not all debt needs to be paid immediately. Some debt sits in a module nobody touches. Other debt lives in the critical path of every feature. Prioritization should weight three factors:
Impact on Velocity
Debt in high-traffic code paths costs more than debt in dormant modules. If every sprint, your team spends hours working around a poorly designed service, that service should rank high on the repayment list.
Risk Exposure
Debt in security-sensitive areas (authentication, payment processing, data handling) carries regulatory and reputational risk beyond just velocity. A single vulnerability in an outdated dependency can cost more than a quarter of engineering time.
Compounding Rate
Some debt gets worse over time. A monolithic module that keeps growing will be harder to decompose next quarter than this quarter. A test gap that covers a low-traffic feature becomes critical when that feature gets adopted. Prioritize debt with a high compounding rate even if its current impact feels moderate.
The 20% Rule
Many high-performing teams allocate 15-20% of each sprint to technical debt reduction. Google's internal research suggests this ratio balances feature delivery with codebase health. Below 10%, debt accumulates faster than teams can pay it. Above 30%, stakeholders lose patience with the pace of new features.
The key is consistency. A team that spends 15% every sprint on debt reduction will outperform a team that does quarterly "cleanup sprints" because small, frequent improvements compound while big-bang refactors carry high risk and often get postponed.
Building a Business Case for Refactoring
Engineering leaders often struggle to secure time for debt reduction because the benefits feel intangible to non-technical stakeholders. Building a business case requires translating technical debt into business language.
Frame Debt as a Tax
Every feature your team builds while carrying significant debt costs more than it should. If debt adds 30% to development time (a figure supported by multiple industry studies), then a feature estimated at 10 days really takes 13 days. Over a year, across all features, that tax adds up to months of lost velocity.
Quantify the Cost
Calculate what your team spends on debt-related work. Track hours spent on:
- Workarounds for known issues
- Regression bugs in debt-heavy modules
- Extended onboarding due to undocumented complexity
- Incident response caused by infrastructure debt
According to a 2024 report from Stepsize, the average engineering team spends 33% of its time on technical debt-related work. For a team of 10 engineers at an average fully loaded cost of $200,000 per year, that represents $660,000 annually in debt tax.
Show the ROI
Refactoring projects should have measurable outcomes:
- "Reducing deployment time from 45 minutes to 5 minutes saves 8 hours per week across the team."
- "Decomposing the order service will reduce the average time for checkout-related features from 3 weeks to 1 week."
- "Adding integration tests for the payment module will reduce payment-related production incidents by an estimated 60%."
Connect each refactoring effort to a metric that leadership already tracks: velocity, incident rate, time-to-market, or customer-facing reliability.
Tie Debt to Strategic Goals
If the company plans to scale from 100 to 1,000 customers next year, infrastructure debt that limits concurrent connections becomes a strategic blocker. If the roadmap includes a mobile app, a tightly coupled monolith that cannot expose clean APIs becomes a strategic liability.
Debt reduction is not engineering housekeeping. It is investment in the organization's ability to execute its strategy. Frame every refactoring proposal this way: "This investment unlocks X capability that the business plan requires." Leaders who understand the connection between code health and strategic execution will find room in the roadmap.
When presenting to non-technical leadership, avoid jargon entirely. Do not say "we need to refactor the monolith." Say "the current architecture limits how many features we can ship per quarter, and this investment removes that limit." The substance is the same. The framing determines whether you get approval.
Technical Debt Management Tools
Effective debt management requires visibility. Several categories of tools help teams track, measure, and reduce debt.
Static Analysis
SonarQube, CodeClimate, and similar tools scan your codebase for code smells, complexity, duplication, and security vulnerabilities. They provide dashboards and trend lines that make debt visible over time.
Codebase Intelligence
Platforms like Glue go beyond static analysis by mapping relationships between files, functions, and teams. When you can see who owns what, which modules have a bus factor of one, and where complexity concentrates, debt prioritization becomes data-driven rather than opinion-based.
Dependency Scanning
Dependabot, Snyk, and Renovate track outdated and vulnerable dependencies. They automate pull requests for version bumps and flag security issues before they become incidents.
Architecture Decision Records
ADRs are not software tools, but they are a debt prevention tool. Documenting why decisions were made prevents future developers from accidentally undoing intentional tradeoffs or repeating mistakes.
Issue Tracking Integration
Whatever tool your team uses for project management (Jira, Linear, ClickUp), create a dedicated label or tag for technical debt items. This makes debt visible alongside feature work and prevents it from disappearing into a separate backlog that nobody checks.
Prevention Strategies
Paying down existing debt matters, but preventing unnecessary debt accumulation matters more. The following practices reduce the rate at which new debt enters your codebase.
Code Review Standards
Define what "good enough" means for your team. This is not about perfection; it is about shared standards. When reviewers consistently flag the same patterns, debt creation slows because developers internalize the standards.
Automated Quality Gates
Run linters, type checkers, test suites, and complexity checks in CI. If a pull request increases cyclomatic complexity beyond your threshold or drops test coverage below your baseline, the pipeline should flag it.
Refactoring as Part of Feature Work
The Boy Scout Rule: leave the code better than you found it. When a developer touches a file to build a feature, encourage small improvements to the surrounding code. Rename a confusing variable. Extract a duplicated block. Add a missing test. These micro-improvements compound over time and prevent debt from growing in active areas.
Architecture Reviews for Large Changes
Before a team builds a new service, adds a major dependency, or changes a core abstraction, hold a lightweight architecture review. Fifteen minutes of discussion before coding starts can prevent weeks of rework after. This is especially valuable when the change touches areas where nobody knows how the system works.
Technical Debt Budgets
Some teams set explicit budgets: "We will not let our technical debt ratio exceed 8%." When the ratio approaches the limit, debt reduction takes priority over new features until the ratio drops back. This creates a natural feedback loop that prevents runaway accumulation.
Knowledge Sharing
Debt often accumulates in code that only one person understands. Pair programming, internal tech talks, and documentation sprints distribute knowledge and reduce the likelihood that isolated code becomes unmaintainable.
When a team member leaves and takes context with them, the cost of understanding their code is a form of debt. Tools that map code ownership and knowledge distribution help teams identify and address these risks before they materialize.
Incremental Refactoring Windows
Rather than treating prevention as a separate activity, build refactoring windows into your standard workflow. When a developer picks up a ticket that touches a debt-heavy module, add 20% more time to the estimate and use that buffer for targeted cleanup. This approach integrates debt reduction into regular delivery work so that neither activity blocks the other. Over the course of a quarter, these small windows add up to significant improvement without ever requiring a dedicated "tech debt sprint" that competes with feature priorities.
Conclusion
Technical debt is not a failure of engineering discipline. It is a natural byproduct of building software under real-world constraints. The teams that manage it well are not the ones that never take on debt. They are the ones that track it, categorize it, measure it, and pay it down systematically.
Start by understanding what debt you carry. Categorize it using the quadrant model. Measure it with a mix of code metrics and velocity indicators. Prioritize by impact, risk, and compounding rate. Build a business case that speaks the language of your stakeholders. Prevent new debt with automated quality gates and consistent review standards.
Technical debt is a conversation your team needs to have honestly and regularly. The cost of ignoring it grows every sprint. The cost of addressing it shrinks every time you do.
The most successful engineering organizations treat technical debt management as a continuous practice, not a periodic event. They build measurement into their pipelines, categorization into their backlogs, and prevention into their culture. The result is not zero debt. It is a codebase that stays healthy enough to support the business at the pace the business needs.
Frequently Asked Questions
What causes technical debt?
Technical debt comes from several sources: time pressure that forces shortcuts, changing requirements that make earlier designs obsolete, lack of knowledge about better approaches, deferred maintenance on dependencies and infrastructure, and insufficient testing or documentation. Most codebases accumulate debt from a combination of all five. The distinction that matters most is whether the debt was taken on deliberately (a conscious tradeoff) or inadvertently (a gap in knowledge or process). Deliberate debt is manageable when tracked. Inadvertent debt signals a need for better practices, mentoring, or tooling.
How do you calculate technical debt?
The most common formula is the Technical Debt Ratio: (Remediation Cost / Development Cost) x 100. Remediation cost is the estimated effort to fix all known debt items. Development cost is the estimated effort to build the system from scratch. Tools like SonarQube automate parts of this calculation by scoring code quality issues and estimating fix times. However, no single metric captures all forms of debt. Supplement the TDR with code churn analysis, complexity metrics, and developer experience surveys for a complete picture. You can use a technical debt calculator to run an initial estimate for your codebase.
Is all technical debt bad?
No. Deliberate, prudent technical debt is a legitimate business strategy. Shipping a feature with a known shortcut to meet a market window, with a plan to revisit it next quarter, can be the right call. The debt becomes problematic when it is untracked (nobody remembers the shortcut was intentional), unmanaged (there is no plan to fix it), or compounding (it makes every subsequent change in that area harder). The goal is not zero debt. The goal is manageable, well-understood debt that does not silently tax your team's velocity.
How much time should teams spend on tech debt?
Industry research and practitioner experience converge on 15-20% of sprint capacity dedicated to technical debt reduction. Google's internal guidance aligns with this range. Below 10%, debt tends to accumulate faster than teams can address it. Above 30%, feature delivery slows to the point where stakeholders lose confidence. The exact percentage depends on your codebase's current health, the pace of new feature development, and your team's tolerance for the friction debt creates. The most important factor is consistency: a steady 15% every sprint outperforms sporadic "tech debt sprints" because regular maintenance compounds while big-bang efforts carry high risk and are often postponed.