To fix AI-generated code, start with an audit, not a rewrite. Check six things: tests, the data model, authorization and secrets, duplicated logic, dependencies, and the deploy pipeline. Then refactor wherever the foundation is sound, which is most of the time, and rebuild only the parts where the data model or architecture actively blocks what the business needs. Fix security first, then make deploys and schema changes safe, then add tests around the money paths, and only then start cleaning up.

We have written about why AI-generated code breaks in production. This post is about the next question: it has broken, or is about to, so what do you actually do?

When a vibe coded app starts to wobble, the temptation is strong and understandable. The app feels fragile, nobody fully trusts it, and starting again feels clean. Sometimes that instinct is right. More often it is the expensive version of a problem that has a cheaper answer. The way to tell the difference is to look before you decide.

Start with an audit, not an opinion

The worst refactor vs rebuild decisions are made on feel. A developer opens the codebase, sees unfamiliar patterns, and declares it unsalvageable. Or a founder, burned by a few outages, decides the whole thing is cursed.

Neither is evidence. Ugly code that works is a cosmetic problem. Clean-looking code with no authorization checks is a serious one. You need to know where the damage actually is, how deep it goes, and whether it is concentrated or spread across every file.

That is what an AI generated code audit is for. Whether it comes from an in-house senior engineer or from outside code audit services, it should take days, not weeks, and it should end with a written list of findings ranked by risk, not a vague verdict.

The AI-generated code audit checklist

Here is what to look at, and what good and bad look like for each.

Tests

Are there any? If so, do they test behaviour that matters (pricing, permissions, payments) or just that components render? Do they run automatically on every change?

No tests is common and fixable. It does not mean rebuild. It means the first refactors have to be preceded by tests that pin down what the app currently does.

Data model

Can you recreate the database schema from files in the repository? Do tables reflect real business concepts, or did they grow one prompt at a time? Are there columns that store the same thing in two places, or relationships that only exist in application code?

This is the most important item on the list, because the data model is the hardest thing to change later. Messy code on a sound schema is a refactor. A schema that cannot represent how your business works is the strongest rebuild signal there is.

Authentication, authorization and secrets

Does every endpoint that reads or writes user data check that this user may touch this specific record? Are any keys bundled into the browser? Are secrets in the repository history? Is row-level access enforced in the database, the API, or nowhere?

Findings here are urgent, but they are almost always fixable in place.

Duplication

Pick your three most important business rules and search for them. How many copies of each exist? Do the copies agree?

Duplication is a cost multiplier on every future change. It is also very refactorable: you choose one copy, put tests around it, and route the others to it.

Dependencies

How many packages are there, how out of date, and how many have known vulnerabilities? Are there two libraries doing the same job? Is there a lockfile, so builds are repeatable?

Old dependencies are routine maintenance. Dependencies that are abandoned, or a framework version so far behind that upgrading means rewriting, start to tip the balance.

Deploy pipeline

Can someone other than the original builder deploy the app? Is there a staging environment? Can you roll back a bad release in minutes? Are there logs and alerts, or do you hear about outages from customers?

A missing pipeline is a gap, not a verdict. It is usually one of the faster things to fix, and it makes every other fix safer.

Refactor vs rebuild: the signals that matter

Once the findings are on paper, the decision gets much less emotional.

Signals that point to refactoring

  • The data model broadly matches the business, even if it needs tidying.
  • The problems are concentrated in a handful of areas, such as auth, config and deploy.
  • The stack is mainstream and maintainable by the team you have or can hire.
  • The app works for users today, and the issue is safety and speed of change, not core function.
  • You can name the specific fixes, and the list is finite.

Signals that point to rebuilding (all or part)

  • The data model cannot represent how the business works, and fixing it means touching nearly everything.
  • The stack cannot meet a hard requirement, such as offline support, a compliance need, or a scale target the architecture structurally cannot reach.
  • Every change breaks something unrelated, even after you add tests, because responsibilities are tangled across the whole codebase.
  • The app is small enough that rebuilding it is genuinely cheaper than understanding it.

Bad reasons to rebuild

"The code is ugly." "We don't like the framework." "AI wrote it, so we can't trust any of it." None of these is a technical argument. The lines AI writes are usually competent. What tends to be missing is structure, and you can add structure to an existing codebase.

A decision table

Use this as a starting point, not a formula. Most real apps have a mix, and the overall answer comes from which column holds the biggest risks.

Audit finding Lean refactor Lean rebuild
No tests Add tests around critical paths first Only if the code cannot be tested without restructuring everything
Schema changed by hand, no migrations Capture the current schema as a baseline migration Schema itself is wrong for the business
Missing authorization checks Add checks endpoint by endpoint, plus database policies Rarely a rebuild reason on its own
Keys in the browser bundle Rotate keys, move calls server side Never a rebuild reason
Core logic duplicated Consolidate into one tested module Duplication is everywhere and copies disagree on purpose
Outdated dependencies Upgrade in steps Framework is abandoned or upgrades require a rewrite anyway
No deploy pipeline Build one around the existing app Never a rebuild reason
Stack cannot meet a hard requirement Replace only the affected part The requirement touches the whole app

Notice how few rows lead to a full rebuild. The ones that do are about the foundation: the data model and the architecture. Everything else is repair.

The middle path: replace it piece by piece

When some parts genuinely need rebuilding, you still rarely need a big-bang rewrite. The safer option has a name: the strangler fig pattern.

It works like this. You put a routing layer in front of the existing app. You pick one area, say billing, and build its replacement properly, with tests, migrations and clear boundaries. You route billing traffic to the new code while everything else keeps running on the old code. When the new billing is proven, you pick the next area.

The advantages are practical:

  • The business never stops. Customers keep using the app the whole time.
  • Risk is small and reversible. If a new module misbehaves, you route back to the old one.
  • You learn as you go. Each replaced piece teaches you what the old system was really doing, including the edge cases nobody documented.
  • You can stop. If, after three modules, the remaining code is good enough, you keep it.

The pattern needs discipline about data. Two systems writing to the same tables need clear ownership rules, or you trade one mess for a more confusing one. Decide which side owns each table, and move ownership deliberately.

How to fix AI-generated code: what to fix first

Whether you refactor, rebuild in part, or a bit of both, the order matters. This is the sequence we follow in application modernization and AI app stabilization work.

  1. Stop the bleeding. Rotate any exposed keys, remove secrets from the client, and close authorization holes on endpoints that touch customer data. This is about liability, so it comes before anything else.
  2. Make sure you can recover. Confirm backups exist and that you have actually restored one. Capture the current schema as a baseline migration so the database can be recreated from the repository.
  3. Make deploys repeatable and reversible. One command or one button to ship, the same to roll back, a staging environment that matches production, and basic logging and alerts. Our cloud and DevOps work often starts here.
  4. Pin down current behaviour. Write tests that capture what the money paths do today, before changing them. These are sometimes called characterization tests: they describe the system as it is, so you notice when a refactor changes it.
  5. Consolidate the core rules. Merge duplicated business logic into one tested place, one rule at a time.
  6. Upgrade dependencies in steps. Small, frequent upgrades with tests running, not one giant jump.
  7. Then go back to features. By now changes are smaller, safer and faster, which is the point of the whole exercise.

Steps one to three are where most of the risk reduction happens, and they are the same whether you end up refactoring or rebuilding.

A rough way to compare the cost

You can sanity-check the decision with simple arithmetic. These figures are an example, not a benchmark. Plug in your own.

Say the audit's fix list comes to roughly eight weeks of work for two engineers. That is sixteen person-weeks. Now estimate the rebuild: say three engineers for four months, roughly fifty person-weeks, plus the old app still needing fixes while the new one is built, plus the weeks spent rediscovering behaviour nobody wrote down.

Multiply each by your rate. In this example the refactor is a fraction of the rebuild before you even count the risk of the rebuild running late. The comparison only flips when the fix list is so long, or the foundation so wrong, that the refactor estimate approaches the rebuild estimate. When it does, partial replacement is usually still cheaper than total.

Where to go from here

If your app is wobbling, resist deciding anything this week except step one: close the security holes. Then get the codebase read properly, by someone who will give you a written list of findings rather than a feeling. With that list in hand, refactor vs rebuild is usually an easy call.

If you want a second pair of eyes, book a free 30-minute discovery call. We will talk through what you have, and you will get a written estimate within two business days.