That moment doesn't arrive suddenly. It accumulates. Every shortcut taken under deadline pressure, every component built without tests, every third-party library left unupdated, each one is a small withdrawal from an account you didn't know you were spending.
By the time technical debt becomes visible, it's expensive. The goal is to catch it while it's still manageable.
Not all technical debt is bad
This is worth saying clearly: taking on technical debt deliberately, with a plan to address it, is a legitimate engineering trade-off. Shipping a working product with some rough edges in Q1 so you can validate product-market fit is a reasonable decision. The problem is the debt that was going to be addressed in Q2 and is still there three years later.
The debt that compounds fastest is never the obvious stuff. It's the architectural decisions that seemed fine at the time and become load-bearing walls you can't move.
The types that actually kill velocity
Architectural debt is the most expensive. A monolith that should have been split into services two years ago. Synchronous operations in critical paths that should be async. A database being used as a message queue. These create bottlenecks that every new feature has to route around.
Test coverage debt is the one that causes 2am incidents. Code that works until it doesn't, and nobody knows why, because there are no tests to tell you what changed. The longer you go without tests, the more expensive it becomes to add them.
Dependency debt is the quiet one. Libraries three major versions behind. Security vulnerabilities in packages you didn't even know you were using. The project still running on Node.js 14. These don't cause problems until they cause a critical one.
The most dangerous technical debt isn't the code that's visibly broken. It's the code that works fine right now, at current scale, with the current team.
How to measure it before the conversation with your board
You don't need a perfect measurement framework. You need a consistent one.
DORA metrics (deployment frequency, lead time for changes, change failure rate, time to restore) are the best proxy for codebase health that leadership can understand. A team deploying multiple times daily with a low change failure rate has a fundamentally different debt profile to one deploying monthly with 20% rollback rates. Collect these numbers. They tell the story better than any code audit.
Hotspot analysis is the other one worth doing: look at which files are changed most frequently and have the highest complexity. That intersection with high change frequency, high complexity is where your incidents live. Tools like SonarQube or even basic git log analysis surface it quickly.
The architectural patterns that age well
The codebase that's still maintainable at 5x the size shares a few traits. Modules and services bounded by business domain rather than technical layer; orders, customers, inventory, rather than frontend/backend/database. Teams can work independently. Failures are isolated. The dependency graph stays legible.
The strangler fig pattern for legacy migration: incrementally replace functionality while routing new traffic to new implementations, rather than attempting a big-bang rewrite. Big-bang rewrites fail more than they succeed. They run over time, lose institutional knowledge, and often ship something that's technically newer but no better designed. Strangle incrementally: prove the pattern, expand from there.
Performance: the debt that waits for 10x
Performance problems at current scale are warnings. At 10x they're outages. The patterns that look fine at 1,000 daily active users and create incidents at 100,000 are almost always detectable before they become critical.
N+1 database queries; individually trivial, catastrophic at volume
Missing indexes on foreign keys; queries that run in 50ms at current data size, run in 8 seconds at 100x
No caching layer; every request hitting the database for data that changes once a day
Bundle sizes that haven't been audited since the project started; page load times that are acceptable on a fast connection, broken on a 4G mobile
The engineering investment required to fix these is modest when caught early. The incident management cost when they surface in production is not.