Tech debt: when to pay it, when to ignore it (with the calculation)

Most teams handle tech debt with permanent guilt and a tech-debt sprint that never quite happens. Here's the practical version — three categories (compounding, static, frozen) that need different handling, the cost calculation that decides whether to pay, five anti-patterns that waste tech-debt budget, and how much of a sprint should be debt work (10-25%, with the why).

May 5, 2026  ·  12 min read  ·  SprintFlint Team

Every engineering team has tech debt. Most teams handle it with a permanent feeling of guilt and a vague intent to “do a tech-debt sprint” that never quite lands. The result: debt that should have been paid five sprints ago is still there, debt that doesn’t actually matter eats hours of refactoring time, and nobody can tell which is which.

This is the practical version. What tech debt actually is. Three categories that need different handling. The rough calculation that decides whether a piece of debt is worth paying. Five anti-patterns that waste your tech-debt budget. And how much of a sprint should be debt work — for real, with numbers.

What tech debt actually is

The word is overloaded. Three different things get called tech debt:

  1. Deliberate, taken on knowingly to ship faster. “We need this in prod by Friday — we’ll skip the migration tooling and clean up after.” This is the original metaphor: a loan that compounds interest until paid.
  2. Accidental, from drift. “We didn’t notice that this part of the codebase was getting messier sprint by sprint until it became a swamp.” No specific shortcut was taken; the system just rotted.
  3. Knowledge debt — disguised as code debt. “Nobody who built this is still on the team.” The code might be fine; what’s missing is people who understand why it’s that way.

Each kind needs different handling. Don’t lump them. The rest of this post mostly addresses (1) and (2) — knowledge debt is a separate problem with separate fixes (better docs, pairing rotation, ADRs).

The rough calculation: when is paying it worth it?

For any specific piece of debt, three questions:

  1. How much is it slowing the team down right now, per sprint? (estimate as a percentage of velocity lost — 5%, 10%, 30%)
  2. How long would it take to pay down? (in points or person-days)
  3. What’s the half-life — how long until this code goes away anyway? (3 months? 2 years? infinite?)

If cost-of-paying < (slowdown-per-sprint × number-of-sprints-until-it-goes-away), pay it.

Worked example:

Slow database migrations are eating ~15% of the team’s velocity every sprint. Fixing the migration framework would take ~20 points (one engineer, one sprint, mostly). The team plans to keep this codebase for at least the next year — say 24 sprints.

Total slowdown if untouched: 15% × 24 sprints = ~3.6 sprint-weeks of lost velocity.
Cost to fix: 20 points = ~1 sprint of capacity.

Pay it. The math is overwhelming.

Counter-example:

Some legacy admin views use a deprecated form-builder. They’re slow to maintain (~5% velocity drag for the engineer who works on them). Fixing them would take ~15 points. The product manager says the entire admin section is being rewritten in Q3 (8 sprints away).

Total slowdown if untouched: 5% × 8 sprints = 0.4 sprint-weeks of lost velocity.
Cost to fix: 15 points = ~0.75 sprint-weeks.

Don’t pay. The rewrite kills the debt for free.

The calculation isn’t supposed to be precise. It’s supposed to make the decision visible. When it’s overwhelming, you act. When it’s borderline, the cost of debating outweighs the savings either way — pick something easy to revert and move on.

The three categories that need different handling

Once you have the calculation, sort each piece of debt:

Compounding debt — pay aggressively

Debt that gets more expensive as the team works around it. Symptoms: every new feature in this area requires touching the rotten part. Test runtime that grows faster than the codebase. CI flakiness that consumes more time each sprint.

Compounding debt is the dangerous kind. The cost calculation is misleading because the slowdown grows over time. The team usually realises this six months too late.

Handling: budget for it explicitly. Even one engineer one sprint is often enough to break the compound. Don’t wait for a “tech debt sprint” — that’s the version that never happens.

Static debt — pay opportunistically

Debt that’s annoying but not getting worse. Old code that works fine, just not how anyone would write it now. A dependency three minor versions behind.

Handling: scout’s-rule it. When you’re already in the file for feature work, leave it slightly cleaner. Don’t open dedicated stories for static debt unless the calculation says it’s worth a focused fix.

Frozen debt — leave it alone

Debt in code that the team rarely touches and that’s stable. A 2018 admin script that runs nightly without complaint. Legacy CSS in a section nobody styles anymore. Code scheduled to be removed.

Handling: ignore. Touching frozen code introduces risk for negligible gain. Engineers who can’t resist refactoring frozen code are usually engineers who want to feel productive — redirect them to compounding debt instead.

The mistake most teams make: treating all debt as if it were compounding. They burn capacity on static and frozen debt while compounding debt accumulates in the corner.

Five anti-patterns that waste your tech-debt budget

1. The “tech-debt sprint” that solves nothing

A whole sprint of pure tech-debt work. Sounds productive; usually isn’t. Without scope discipline, the team picks the easy debt (low-risk, low-reward static debt) and avoids the scary debt (the legacy auth flow nobody wants to touch). End of sprint: lots of small commits, no actual leverage gained.

The fix: budget tech debt as a percentage of every sprint (10-20%), not as a sprint of its own. Pay debt continuously rather than in batches.

2. The rewrite gambit

“Let’s rewrite the whole module from scratch.” Sometimes correct, usually disaster. The rewrite takes 3-5x the estimate. Mid-rewrite, business priorities shift. The half-rewritten state is worse than either the old or the new.

The fix: incremental migration with both versions running. Strangler pattern. Reach a state where the new is provably handling X% of traffic before deleting the old. Yes, this means complexity overlap for months. The alternative is the half-rewrite that never finishes.

3. Refactoring without a target

“I’m going to clean up this file.” For what? Refactoring without a use in mind tends to optimise for engineer aesthetics rather than team velocity. The file becomes prettier; nothing works better.

The fix: refactor in service of the next feature. If you’re about to add functionality to a function, refactor that function to make the addition cleaner. Don’t refactor functions you’re not about to extend.

4. The estimate-killing perfectionist

One engineer turns every story into a tech-debt mission. A 3-point ticket becomes a 13-point refactor because “I noticed this file needed work.” The sprint slips; the original feature ships late.

The fix: refactoring inside a feature story is fine if it doesn’t change the estimate by more than ~30%. Past that, it’s a separate story that should be visible to the team.

5. Debt that’s not actually debt — it’s “I would have written this differently”

A surprisingly large fraction of “tech debt” is one engineer’s preference vs another’s choice. ORM vs raw SQL. Class-based React vs hooks. Tabs vs spaces in YAML. None of these are debt in the cost sense; they’re stylistic disagreements.

The fix: a piece of code is only debt if it costs the team velocity now or will compound. Personal preferences don’t qualify. The team’s linter and architecture decisions handle stylistic divergence — don’t relitigate them as debt.

How much of a sprint should be debt work?

The honest range: 10-25%, depending on the codebase’s age and the team’s recent shipping pressure.

  • 5%: the team is in active firefighting mode (incident response, urgent feature pressure). Debt accumulates but the team accepts it consciously.
  • 10-15%: healthy steady-state for a 2-3 year old codebase with active product development.
  • 20-25%: maintenance mode, or a codebase the team inherited and is bringing under control.
  • >30%: something is wrong. Either the codebase is so bad that pure feature work is impossible, or the team is using “tech debt” as cover for not shipping.

Communicate the percentage to stakeholders. “We spend ~15% of every sprint on infrastructure we’ll only feel six months from now” is a defensible answer. “We’re paying down debt as needed” is not.

The signal that debt is being mismanaged

Three patterns to watch for:

“We need a tech-debt sprint”

Said once a year, executed maybe half the time. If the team needs a tech-debt sprint, debt has been allowed to accumulate well past the point where it should have been paid. Fix the allocation, don’t fix the symptom.

“We can’t ship this feature without a refactor first”

Translates as: the file we need to touch has been left alone for so long it can’t safely accept new work. This is compounding debt that wasn’t caught. Now you pay both the refactor and the feature, in series.

“Our refactor became another refactor”

The “I’ll quickly clean this up” pattern that snowballs into a 5-day refactoring expedition. Either timebox aggressively (one day, then commit-or-revert), or convert it into a real story with real estimates.

When tech debt isn’t the problem

A common confusion: blaming tech debt for problems that are actually about process or tooling.

  • Slow CI? That might be tech debt (test bloat) or it might be tooling (CI runner sized wrong, parallelism not set up). Diagnose before refactoring.
  • Mid-sprint scope creep? Not debt. That’s scope-change handling.
  • Velocity dropped? Could be debt, could be people changes, could be story-point recalibration. (See velocity dropped — what to do.)
  • “Code is hard to understand”? Could be debt, could be missing docs, could be missing onboarding.

Diagnose before paying. Tech debt is the convenient answer; it’s often not the right one.

Bottom line

Tech debt isn’t a permanent moral failing — it’s a calculation that should produce a sprint-level decision.

Sort it: compounding (pay aggressively), static (opportunistic), frozen (leave alone). Run the rough calculation: cost-to-pay vs slowdown × time-until-this-code-goes-away. Allocate 10-25% of every sprint to debt continuously, not in batched sprints.

Don’t refactor without a target. Don’t rewrite the whole thing. Don’t dignify personal preferences as debt. Don’t let the perfectionist eat the sprint.

The teams that get this right ship steadily for years. The teams that don’t oscillate between feature crunches and tech-debt rescues, never quite getting ahead.

Pick a number. Defend it. Adjust quarterly.

Stop estimating in hours.

SprintFlint runs your sprints with story points, velocity, capacity, and retros built in. First 300 tickets free, no credit card.