Technical debt has a precise, unsentimental definition: it is whatever makes the next change more expensive than it should be. AI-generated codebases accumulate it in a recognizable pattern, and the symptom is always the same curve: feature one took an hour, feature five took an afternoon, feature ten took a week and broke feature two. This article is about reading that curve in your own project, deciding which debt matters, and paying it down in an order that buys speed back fastest.
Quick answer: AI code debt shows up as duplicated logic, dead code, three styles doing the same job, zero tests, and configuration scattered through files. Pay it down in order: tests on the flows that make money, a deploy pipeline that runs them, secrets into configuration, then deduplication. Never rewrite for style points.
What does AI technical debt look like?
Open the repo and the patterns are visible fast. The same logic implemented three ways in three files, because each generation session solved the problem fresh. Dead code: components and functions nothing calls, left over from abandoned directions. Mixed conventions, where the data layer changes philosophy halfway through the project. Values that should be configuration (URLs, keys, limits) hardcoded wherever they were first needed. Giant files that accreted every related feature. And the defining absence: no tests, anywhere, so every one of the above is load-bearing until proven otherwise. None of this means the app is bad. It means the app was generated by a process with no memory and no reviewer, and it looks exactly like that.
Why does velocity collapse?
Three compounding reasons. Regression fear: with no tests, every change is a bet that nothing else depended on what you touched, so changes get slower and more timid. Context cost: duplication and mixed patterns mean the AI (and any human) must understand more code to change anything safely, and understanding is the expensive part. And coupling: logic that should be shared but is instead copied means one business rule change becomes a three-file scavenger hunt, and missing a copy becomes a bug. This is the same mechanism behind the doom loop, experienced as a slow leak instead of a crisis.
What debt is fine to keep?
More than purists admit. Ugly code that works, is covered by a test, and rarely changes is not debt in any meaningful sense; it is paid-off housing. Duplication in genuinely separate corners of the app costs little. Unfashionable patterns cost nothing at all. The debt worth paying down is the debt on the paths that change often and the paths that earn money, because that is where the interest accrues. A codebase audit that ends with rewrite everything is a bad audit; the useful output is a short list ranked by which fixes make next month’s work cheaper.
What is the paydown order?
- End-to-end tests on your critical flows: signup, login, the core action, checkout. These protect revenue and make every later step safe. Days of work, and the highest return in the whole list.
- A pipeline that runs them: build, lint, tests on every push, so verification is automatic rather than aspirational.
- Secrets and configuration out of the code and into environment variables, with anything ever committed rotated.
- Deduplicate the logic that changes: pricing rules, permissions, validation. One source of truth for each rule the business edits.
- Structure last: split the giant files, settle on one pattern per layer, delete the dead code. Cosmetic gains, real but cheapest to defer.
Notice what the order optimizes: safety first, then change speed, and appearance last.
How do you keep the AI from re-creating debt?
Give it the memory and the reviewer it lacks. A conventions file in the repo (most tools support rules files) stating the patterns, the shared modules to use, and the things never to do. Small scopes per session: one feature or one fix, on a branch, rather than open-ended improve requests. Review the diff, even lightly; you are checking not for cleverness but for surprise, and surprise in a diff is where debt enters. And keep the tests from step one running, because they convert debt from silent to loud, which is the entire battle.
When is debt a rebuild signal?
Rarely, and the honest tells are specific: the data model is wrong at the foundation (the entities themselves rather than their formatting), the framework is fighting the product’s actual shape, or the security debt is so pervasive that verifying the fix costs more than regenerating with guardrails. Volume of ugliness alone is never the signal, since ugliness with tests is workable. If the audit finds one of the true tells, that decision deserves its own framework, which is the next article in this series. If you want the ranked debt list for your own app without doing the archaeology yourself, that is exactly what the production audit produces, and the pillar checklist shows where debt paydown fits in the larger launch picture.
Frequently asked questions
Should I ask the AI to refactor the whole codebase?
No. A sweeping refactor without tests is the doom loop with better intentions: mass unverified change. Refactor incrementally, behind tests, one module per session, and only where the debt is charging interest.
How much does adding tests cost?
For end-to-end coverage of three to five critical flows: a few days of focused work, whether yours with AI assistance or a developer’s. It is the least glamorous spend in software and reliably the best-priced insurance you can buy for an app that makes money.
Is duplicated code always bad?
No. Duplication of stable, simple things is rent-free. Duplication of business rules that change (prices, permissions, validations) is the expensive kind, because change means finding every copy and missing one means a bug. Pay down the second kind.
What is a rules file?
A file in your repo that the AI tool reads before generating: your conventions, preferred libraries, shared modules, and forbidden patterns. Ten minutes to write, and it meaningfully raises the floor of every future generation session.
How do I measure whether debt is improving?
Three usable signals: how long a small change takes end to end, how often a change breaks something unrelated, and how much of the app the tests cover. Track them loosely month over month; the trend matters more than the numbers.
Will a developer judge my AI-written code?
A professional will read it the way a mechanic reads an engine: symptoms and causes rather than character. We have spent twenty years in human-written codebases with the same problems and less excuse. The code is a starting point, and usually a workable one.