RU Send your project
All articles

Technical debt in a vibe-coded app: see it, size it, pay it down

How to find the debt that actually slows you down, put it in terms people understand, and pay it off without stopping feature work.

· 4 min readCode

Every product has technical debt, and on its own that’s fine. The trouble is debt nobody knows about until it eats a week on a one-day task. In apps built with an assistant, it piles up faster than usual and looks a bit different.

What debt looks like in vibe code

In a typical project, debt comes from hurry: someone cut a corner and promised to come back. In a vibe-coded project, it comes from every prompt solving its problem from scratch.

  • The same code in five places. Form validation, price calculation and plan checks copied into every component that needed them, and by now slightly different.
  • Several ways to do everything. Data loaded through three different libraries; state living in context, in a store and in the URL, depending on which prompt wrote it.
  • Dead code. Abandoned screen variants, unused functions, components called PricingOld and PricingNew2.
  • No boundaries. UI components query the database directly, business rules live in button handlers, and the types at the API boundary are any.

Where to look

Don’t try to catalog all of it at once. There’s too much, and most of it isn’t in your way. Look where it hurts.

Your history shows which files change most often:

git log --since="6 months ago" --format= --name-only \
  | sort | uniq -c | sort -rn | head -20

A file that changes often and keeps producing bugs is your prime candidate. A file that’s awful but hasn’t been touched in a year can wait. Debt with no interest doesn’t need paying.

Then ask the team. Where are estimates always too low? Which parts does everyone avoid? What do you have to explain to every new person? The answers usually line up with what git showed you.

How to size it

Each debt item needs two estimates: what it costs to fix, and what it costs while it stays unfixed. The second matters more and gets forgotten more.

“Price calculation in five places” isn’t “ugly”. It’s “every pricing change takes two days instead of two hours, and last time we missed one of the places”. Phrased that way, debt can be weighed against features and discussed with whoever decides what happens next.

Keep a simple register: what, where, how it gets in the way, what it costs to fix. No more than twenty items. Nobody reads a long list.

Paying it down without stopping work

A dedicated “refactoring sprint” almost never works. It gets postponed, then trimmed, then its results drown in new features. Here’s what does work.

  • Pay down debt where you’re already working. If a task touches price calculation, consolidating that calculation is part of the task. Debt gets paid next to features, not instead of them.
  • A fixed share. Agree that a noticeable part of every cycle, say a fifth, goes to items from the register. Decided in advance, not “if there’s time left”.
  • Most-frequent first. Sort the register by how often an item gets in the way, not by how ugly it is.
  • Delete. Dead code is the cheapest debt. It doesn’t need rewriting, just removing. Start there; you’ll see the result the same day.
  • Lock it in. Once logic lives in one place, add a test and a lint rule so the next prompt doesn’t scatter it again.

How to tell it’s getting better

Watch the same things you started with: how long a typical change takes, how often a change in one place breaks another, how many register items are closed. If those haven’t moved after a couple of months, you’re paying off the wrong debt.

SUBXCAT helps build that register for projects made with an assistant and pay it down alongside regular development.

Want us to do this for you?

Tell our assistant about your project — a rough estimate in five minutes, a review in 48 hours.

Book an intro call 20 minutes: an engineer, a designer and a marketer look at your project with you.
Book a call