In the 21 third-party apps AxonBuild audited in June and July 2026, Maintainability & Evolvability averaged 61.1 out of 100. Reliability & Correctness averaged 31.4. The first ranked near the top of the twelve pillars scored. The second ranked last. The averages were nearly thirty points apart. That difference does not show whether the two scores rose or fell together in each app. The corpus holds no conventionally built comparison group, so it cannot say AI code carries more debt than human code. It can describe the relative pillar averages in this selected cohort.
Much of the advice about vibe coding technical debt assumes a team: a PR process, a second reviewer, and a spec written before the agent builds. Those controls can help, but they do not tell a solo builder which part of today’s repository deserves attention first. This post uses three inspectable signals to create that shortlist without pretending they add up to a universal debt score.
The median review score across those 26 apps was 51 out of 100 (the corpus methodology and denominators live with the 26-app study itself). In the 21-app third-party subset, reliability averaged lower than maintainability. These are web apps: mostly Next.js or Vite React with TypeScript, sitting on Supabase and similar managed backends, deployed to Vercel or Cloudflare, and one of them is a straight Bolt.new export. Lovable-style prompt-to-app stacks are overrepresented, and the audits did not record a named builder for every app.
The rest of this post covers why that gap forms, what the wider research shows, how to inspect the same signals in your own repository, and how to pay down confirmed debt without a team.
What technical debt actually means, in one paragraph
Technical debt is the extra cost every future change carries because of the state the code is already in. Ward Cunningham coined the metaphor, and Martin Fowler’s definition is the one most people are reaching for: software systems build up “cruft”, meaning deficiencies in internal quality that make the system harder to modify and extend than it would ideally be. The extra effort each later feature costs is the interest on that debt, and cleaning up the structure pays down the principal, which Fowler advises doing gradually rather than as one project. Nothing in the definition says who or what wrote the code, so it applies unchanged to a repository generated from prompts. The term means the same thing in an AI-built app. What changes is that nobody remembers taking on the debt, which turns paying it down into a discovery problem first and an engineering problem second.
Why AI-generated debt piles up faster than debt you wrote yourself
Debt you wrote yourself came with a memory. You know which shortcut you took, which case you skipped, and roughly where the body is buried. Debt generated from a prompt arrives without that memory, and four conditions give it room to accumulate; no matched comparison in the 26-app corpus measures the speed against hand-written debt.
The first is that the decision never appears in the diff. When you ask for a signup flow, the model picks a session strategy, an error-handling style, a place to validate input, and a shape for the data. None of those choices show up as a choice. They show up as finished code, and a finished file reads like a decision that was already made and reviewed. Whether you prompt through Lovable, Base44, Bolt, Replit, v0, Cursor or Claude Code, the same thing happens: the reasoning stays in the chat and the repository keeps only the output.
The second is throughput. A single prompt can produce a few hundred lines in under a minute. Nobody reads a few hundred lines of unfamiliar code in under a minute, so generation runs ahead of review from the first week. The gap does not close on its own, because the fastest way to fix generated code is another prompt.
The third is copy-forward duplication. Asked for a second table, a second dashboard, or a second admin screen, an assistant will usually generate a fresh version rather than find and reuse the one already in the repository. Both copies work on the day they ship. They start costing you the first time one of them gets a fix.
The fourth is the missing yardstick. Without a spec or a test, there is nothing to check the output against except whether the screen looks right. In this corpus, the reliability average was lower than the maintainability average. That comparison does not establish how those measures moved together app by app.
What the wider data shows
AxonBuild’s corpus is 26 apps. The wider research on AI-assisted codebases points the same way, and it is worth knowing what it says before you decide how much of this applies to you.
GitClear analyzed 211 million changed lines authored from January 2020 through December 2024. Its endpoint comparison runs from 2021 to 2024. Over that period, the share of lines classified as copy or paste rose from 8.3% to 12.3%, while the share of moved lines fell from about 25% to under 10%.
Sonar’s State of Code Developer Survey found that 40% of developers say AI increased their technical debt by generating unnecessary or duplicative code, and 53% attributed added debt to AI producing code that looked correct but was not reliable. In the same survey, 88% reported at least one negative effect of AI on their technical debt and 93% reported at least one positive one, which is the honest version of this story.
The 2025 Stack Overflow Developer Survey received 31,476 responses to its multi-select question about AI-tool frustrations. Solutions that are almost right but not quite were named by 66% of respondents. Debugging AI-generated code taking more time was named by 45%. Nearly correct code is harder to debug than code that is plainly wrong.
OX Security, reviewing open-source repositories, found what it calls phantom bugs in 20 to 30% of AI-generated code: over-engineering for improbable edge cases, at a cost in performance and wasted resources. It described AI-generated code as highly functional but lacking architectural judgment.
Two caveats. All four datasets look mostly at professional teams working in existing codebases, not at solo founders shipping a first product, so the shapes transfer better than the exact numbers. And none of them, AxonBuild’s included, compares AI-written code against a matched set of hand-written code from the same teams. Every honest reading here is about where the debt sits, not about a verdict on which kind of code is worse.
What the two pillar averages actually measure
Maintainability & Evolvability is a proxy for how easy a codebase is to extend: module boundaries, naming, and how far a change in one place ripples to another. Across the 21 third-party apps, its 61.1 average was much higher than Reliability & Correctness within the same rubric. That is a relative comparison inside this corpus, not a universal threshold for calling an app maintainable.
Reliability & Correctness asks a different question: does the app catch its own mistakes, and does anything notice when it does not. Across the same 21 third-party apps, its 31.4 average ranked last of the twelve pillars. The nearly thirty-point difference between the pillar averages is the useful finding.
| Looks fine | Actually fine |
|---|---|
| The code reads clean, so the debt must be small. | Across the 21 third-party apps, Reliability & Correctness still averaged 31.4. Reading the code was never testing what breaks. |
| Test coverage is high, so the behavior is protected. | One app in the corpus had an 818-line checkout test suite that never executed the checkout. Coverage counts lines run, not behavior asserted. |
| Two components look the same, so consolidate them. | An admin view and a public view are allowed to diverge. Merging them on principle creates the bug the cleanup was meant to prevent. |
| The audit found no criticals, so the debt is low. | The motorsport dashboard scored 63 with zero criticals while two of its twin components had already drifted apart in behavior. |
Technical debt examples: a dashboard that scored 63 with two components already drifted
I saw a small version of that gap auditing a motorsport dashboard, no criticals, a score of 63. Two of its near-identical table components had already drifted apart: a favorite-toggle feature landed on one twin and never made it to the other, so two views built from the same copied component behave differently today. Nothing failed when that shipped, because nothing was built to notice a difference between components that started out as copies of each other. It read as one of the more finished apps in the corpus, right up until you compared the twins.
How to measure technical debt in AI code
Three quick repository signals can tell you where to start looking for technical debt in AI-generated code: unusually large files, the files churned most in the last month, and function names defined more than once. They are triage signals, not a technical-debt score and not a substitute for testing the app’s behavior.
- 01 Large-file candidates: rank every source file by line count. A file three or four times the size of its neighbors deserves inspection, but size alone does not prove debt
- 02 Churn: rank files by how many times they were touched in the last month. Repeated fixes and reverts can mark an unstable boundary, though active feature work can also create healthy churn
- 03 Possible duplication: count function and component names defined more than once. Review each match because common names, separate scopes, generated files, and deliberate variants create false positives
# biggest files (god-file candidates)
git ls-files -z '*.tsx' '*.ts' | xargs -0 -n 1 wc -l | sort -rn | head
# churn: files revised most in the last month
git log --since='1 month ago' --name-only --pretty=format: | sed '/^$/d' | sort | uniq -c | sort -rn | head
# duplicated logic: function/component names defined more than once
grep -rhoE '(function [A-Za-z0-9_]+\(|const [A-Za-z0-9_]+ ?= ?\()' src | sort | uniq -c | sort -rn | awk '$1>1' | head
Swap the file globs and the src path for whatever your project actually uses (.py, .rb, app/ instead of src/) and run all three. Treat the output as a shortlist for review: a large file can be cohesive, high churn can be healthy feature work, and duplicate names can live safely in different scopes. The signal becomes useful when it lines up with defects, slow changes, repeated reverts, or missing tests.
Tools that go past grep
The three commands above cost nothing and run anywhere, which is why they are the lead. When the shortlist gets long enough to argue about, four tools turn each signal into a number you can track.
- 01 jscpd for duplication. It finds duplicated fragments across files and reports a duplication percentage, and it can fail a build when that percentage crosses a threshold you set. The grep above finds repeated names; jscpd finds repeated code even when the names differ
- 02 The ESLint complexity rule for cyclomatic complexity (radon does the same job for Python). File size is a rough proxy for how tangled a file is; cyclomatic complexity measures the branching directly, per function, so you can find the one 40-branch function inside an otherwise reasonable file
- 03 knip for dead code. It reports unused files, unused exports and unused or unlisted dependencies in JavaScript and TypeScript projects. Generated code leaves a lot of orphans behind, and deleting a file nothing imports is the cheapest debt payment there is
- 04 Static analysis as a category. SonarQube, Semgrep and ESLint's own rule sets scan for code smells and bug patterns without running the app. Every finding still needs the same judgment call as a grep hit, but you get a repeatable baseline instead of a one-off look
Pick one, wire it into the command you already run before shipping, and record the starting number. A duplication percentage that stays flat while the app grows is a real result. A tool you ran once and never again is not.
Reading the signals
AI-generated code technical debt can bill you on three different clocks. A large, tightly coupled file raises the cost of later edits because one change can affect behavior far from the line being changed. A churn spike costs you now when repeated fixes and reverts reveal an unstable boundary. Duplicated logic costs you invisibly when two copies of the same rule drift and users receive different behavior without an obvious error. None of those signals proves debt alone; each becomes actionable when repository history or product behavior confirms the cost.
| Signal | What it costs you | What confirms it is real debt | Common false positive |
|---|---|---|---|
| Large file | Every later edit, because a change can move behavior far from the line you touched | A recent change in that file broke something elsewhere, or you avoid opening it | A long but cohesive file: generated types, a config map, one screen with no branching |
| Churn | Money now, in repeated fixes and reverts around an unstable boundary | The same file appears in three or more bug fixes or reverts in a month | Healthy feature work. A file you are actively building out will churn and should |
| Duplication | Nothing visible, until two copies of one rule drift and users get different answers | The copies implement the same rule and one has already received a fix the other did not | Deliberate variants. An admin view and a public view showing different fields on purpose |
None of these three has to show up in a happy-path demo, the same way debt can hide behind an 818-line test suite that never once executed the checkout it was written to cover: a codebase can look finished and still lack protection around its critical behavior. Why an AI-built app gets harder to change covers the mechanism in more detail: repeated local changes can accumulate without anyone re-evaluating the whole system.
One thing the corpus cannot tell you: whether one builder duplicates more than another. The audits did not record a named builder for every app, so treat the duplication signal as tool-agnostic. The mechanism sits in the prompt loop, not in any one product.
Performance debt wears the same shape with a different symptom. A missing connection pooler or an unindexed foreign key, two of the risks behind an app stalling as concurrency grows, can stay invisible until load forces the issue. Maintainability debt and performance debt can both remain outside the screens you would show in a demo.
The debt in AI-generated code looks like a clean diff, sitting on top of a test that was never written.
Why code review and coverage numbers miss this
Review checks the diff, not the decision. A reviewer reads what changed and asks whether it is correct. The expensive part of generated code is the choice that never surfaced as a choice: the session strategy, the place validation lives, the shape of the data. A correct-looking diff passes review because it is, in fact, correct. It is the assumption underneath it that nobody saw. What happens in a code review, step by step, shows where that limit sits.
Coverage counts lines executed, not behavior asserted. That is how a checkout suite reaches 818 lines without ever executing the checkout: the tests run, the number goes up, and the money path is untouched. A coverage percentage tells you which lines a test process visited. It cannot tell you whether anything would fail if the behavior changed.
Duplication only becomes visible after the fact. On the day two copies ship, they agree, so no review comment and no test catches them. The cost lands weeks later when one copy gets a fix and the other does not. By then the two are separate code with separate histories, and the only thing that would have caught the drift is a check that compares them, which is exactly the check nobody writes for code that started out identical.
How to fix technical debt in AI code without a team
Paying down technical debt in AI code without a team follows a risk-first order: pin tests to the flows that move money or irreplaceable data, split the most costly large file when a real change already takes you into it, then consolidate duplication that has demonstrably drifted. It does not start with starting over. The full cleanup procedure walks the same order at length.
- 01 Pin critical behavior first. Add focused tests around signup, checkout, authorization, and any flow that moves money or irreplaceable data before restructuring the code beneath them
- 02 Split the most costly large file when a real feature already has you in it. Pull it apart along a boundary the current change exposes, such as data access, business rules, and rendering
- 03 Consolidate duplication only after confirming the copies represent the same rule and have begun to drift. Keep one discoverable implementation, migrate its call sites, and let the tests prove behavior stayed intact
Do the three in that order, because each one makes the next one safer. A pinned test tells you whether the large-file split broke the money path, and once those tests exist, naming the file and the command that protects it is what belongs in a CLAUDE.md so the assistant can rerun the same guard next week. A file that has been separated along real boundaries is also easier to inspect for duplicated rules. This work can often begin without a full rewrite or a dedicated cleanup sprint by taking the next risk-reducing step when you are already changing that area.
Paying your own debt down is one slice of whether the app is ready to launch at all. Inheriting someone else’s AI-built app is a related but different job, closer to a first-week review than an ongoing gauge.
Rewrite or rework: how to decide
Start from the default: rewriting the whole app is almost never the answer. A rewrite throws away every decision the app already got right along with the ones it got wrong, and the parts it got right are invisible precisely because they work. What you are actually deciding is much smaller: whether to repair one module in place or rewrite it.
Before choosing either path, write down the module’s required behavior. Add focused regression tests or another repeatable check. Missing protection is a reason to establish it before changing code, not a reason to rewrite first.
- 01 Current behavior: document what the module must do, including edge cases and external contracts. Add focused regression tests or repeatable checks before either repair or rewrite
- 02 Change risk: review coupling, defect history, and platform constraints. A module that cannot be isolated or safely extended may favor replacement. Stable surrounding behavior may favor repair
- 03 Replacement cost: compare the work of recreating behavior, integrations, migrations, and operational knowledge with the cost of repairing the known defects. Choose the path with the lower verified risk and total cost
Do not let missing tests or a single churn threshold decide the path. High churn can come from active feature work. Repair is usually safer when the rules exist only inside the old implementation, because a rewrite may lose them. Write those rules down first. That is the same spec-first habit that keeps the next generated module out of this position. A targeted rewrite can still make sense when coupling, recurring defects, platform constraints, and total replacement cost support it.
What to ignore
Not everything a grep turns up is worth an afternoon. Style disagreements, folder-naming conventions, and a coverage number chased for its own sake feel like progress while reducing no risk. A rename that touches forty files and changes nothing about what the app does is the kind of pay-down that feels productive and buys nothing back.
The same restraint applies to duplication. Two similar-looking components are not automatically debt. An admin view and a public view are allowed to diverge on purpose, showing different fields to different roles, and consolidating those two on principle is what creates the bug the self-measure was supposed to prevent. The three commands only flag where to look. Whether a given god file or a given duplicate is actually costing you something stays a judgment call only you can make.
Common questions about technical debt in AI-generated code
Is AI-generated code more technical debt than human code?
No dataset here can answer that, because this corpus has no comparable set of conventionally built apps. What it does show is the relative pillar averages inside the 21 third-party AI-built apps reviewed: Maintainability & Evolvability averaged 61.1 out of 100, while Reliability & Correctness averaged 31.4 and ranked last of the twelve pillars. The averages were nearly thirty points apart. It is not a verdict that AI code is worse than human-written code.
Wider research points the same direction without settling the comparison either. GitClear found copy-pasted lines rising from 8.3% to 12.3% between 2021 and 2024 while code reorganization fell, and Sonar’s survey found 40% of developers blaming AI for debt from unnecessary or duplicative code.
Why does AI-generated code create technical debt?
Because the decisions behind the code never enter the repository. A prompt produces finished-looking output, and the session strategy, validation placement and data shape it chose arrive as facts rather than as choices anyone reviewed. Generation also outruns review, and an assistant asked for a second version of something will usually regenerate it instead of reusing what already exists. Without a spec or a test to check against, nothing catches any of that until behavior drifts.
How do I measure technical debt in AI code?
Start with three repository signals: rank files by line count to find large-file candidates, rank files by touches in a chosen time window to find churn, and grep for repeated function or component names to find possible duplication. Then review those candidates against defects, change lead time, reverts, and missing tests. The commands create a baseline and a shortlist; they do not produce a defensible technical-debt score by themselves.
What tools measure technical debt in AI-generated code?
Four cover the common signals. jscpd reports a duplication percentage and can fail a build above a threshold you set. The ESLint complexity rule (or radon for Python) measures cyclomatic complexity per function, which is more precise than file size. knip finds unused files, exports and dependencies, and static analysis tools like SonarQube or Semgrep give you a repeatable code-smell baseline.
None of these produces a number that means anything on its own. Their value is the trend: record the starting figure, wire one check into whatever you run before shipping, and watch whether it moves as the app grows.
How is AI technical debt different from normal technical debt?
The debt you write yourself comes with a memory of the shortcut you took. Generated debt does not, so nobody can point at the assumption that was made. It also has more room to accumulate, because code is produced quicker than anyone reads it, though no matched comparison in the corpus measures the speed. In the 21 third-party audits, reliability averaged 31.4 while maintainability averaged 61.1. The repair order is the same as for any debt; the discovery problem is harder.
What are the four types of technical debt?
The four-way split people mean is Martin Fowler’s technical debt quadrant, which crosses deliberate against inadvertent and reckless against prudent. Reckless-deliberate is skipping design because you believe you cannot afford the time. Reckless-inadvertent is mess produced by not knowing better. Prudent-deliberate is a shortcut taken knowingly to make a release, with the cost understood. Prudent-inadvertent is the better design a capable team only recognizes after shipping, which Fowler treats as inevitable rather than as a failure.
Most AI-generated debt lands in the inadvertent half, and that is what makes it awkward to talk about. There is no shortcut anyone can point to and no meeting where a trade-off was accepted. There is only output that nobody evaluated, which is why the discovery step matters more here than the taxonomy does.
How much technical debt is acceptable?
Enough that you can still catch a regression on the flows that move money or irreplaceable data, and no more. There is no universal threshold, so treat any single number as a reference point rather than a pass mark: across the fixed cohort of 26 AI-built apps AxonBuild audited in June and July 2026, the median review score was 51 out of 100, and that corpus holds no conventionally built comparison group, so 51 describes where these apps sat rather than where an app should sit.
What makes debt unacceptable is its position, not its size. Debt sitting under an untested checkout, an unenforced tenant boundary, or a schema that stores the same fact in three places is worth paying down this week, because a mistake there is expensive and nothing would report it. Debt in a settings screen nobody edits can wait indefinitely, and a rename that touches forty files without changing behavior buys back nothing at all.
Should I rewrite my AI-built app or rework it?
Rework it in place when a repair can preserve tested behavior at lower risk and cost. Consider a targeted module rewrite when coupling, recurring defects, platform constraints, and replacement cost favor it. Before either path, document the required behavior and add focused regression checks. Missing tests are a reason to add protection first, not a reason to rewrite.
Can I pay down AI technical debt without a team?
Yes. Start by pinning focused tests to the flows that move money or irreplaceable data. Then split the large file that is demonstrably slowing or destabilizing changes, and consolidate duplicated logic only after confirming that the copies represent the same rule. A solo builder can begin that sequence without turning it into a rewrite, while still bringing in specialist review when the business risk warrants it. What a vibe coding cleanup specialist does, and when one is worth hiring, is its own page.
What is vibe coding technical debt?
It is the debt left behind when an app is built by describing it to an AI rather than writing it line by line. In practice it shows up as untested critical paths, duplicated logic that was regenerated instead of reused, and decisions nobody made explicitly. The code can read well while protection stays weak. Across the 21 third-party audits, the maintainability average was nearly thirty points above the reliability average. That cohort-level difference is easy to miss when you look at code alone.
If you have a working app built with these tools and need it ready for real customers, this is what we do.
Built it with AI. Now it has to hold up for real customers.
The Production Hardening Sprint takes the app you already have and builds the production foundation underneath it. Authentication and access rules, payments that stay consistent, error handling, monitoring, backups, automated tests and a documented handover. Our engineers work inside your existing codebase for ten working days. All 123 deliverables are included, and you get the evidence for each one.
See the Production Hardening Sprint →
$2,500 fixed price · 10 working days · One codebase