Refactor a vibe-coded app when its data model, auth, and core workflows are sound and only the code structure is messy. Rebuild when the data model, security boundaries, or architecture are fundamentally wrong, because no amount of cleanup fixes a bad foundation. Decide with evidence, not frustration: run a timeboxed refactoring spike and score the app against the six signals below.
Tools like Lovable, Bolt, Replit, Cursor, and Claude Code can take an idea to a working prototype in a weekend. The problem shows up in week six, when every change breaks something else and nobody can explain why. At that point founders and tech leads ask the same question: do we clean this up, or start over? Both answers can be right, and both can waste a month if chosen for the wrong reasons.
This guide is a decision framework, not a pep talk. If you have already decided to keep the code, the follow-ups are the 7-step AI-generated codebase audit and the lessons for fixing a vibe-coded codebase before launch.
Refactor vs rebuild: what is the real difference?
A refactor changes the structure of code without changing what the product does. Users see nothing different, and the app keeps running and earning while you work. A rebuild replaces the system, or large parts of it, with new code written against a new design. It resets risk to zero in some areas and introduces fresh risk everywhere else.
There is also a middle path that most teams underuse: strangler-style replacement. You keep the old app live, and rebuild one slice at a time (auth first, then billing, then the core feature) behind the same URLs until nothing of the original remains.
| Approach | Best when | Main risk | Typical shape |
|---|---|---|---|
| Refactor in place | Data model and workflows are right, code is tangled | Endless cleanup with no product progress | Weeks of small, tested changes |
| Strangler replacement | One or two layers are broken, the rest works | Two systems to maintain during the transition | Module by module, behind stable routes |
| Full rebuild | Schema, security model, or architecture is wrong | Re-creating old bugs and losing hidden business rules | New codebase, migrated data, cutover date |
The 6 signals that decide it
Score the app against each signal. Two or fewer red flags usually means refactor. Three or four points to a strangler replacement of the broken layers. Five or six means a rebuild is probably cheaper than the repair, as long as you can write down what the old system does.
1. Is the data model sound?
The database schema is the hardest thing to change and the most expensive thing to get wrong. AI tools tend to create tables as features are requested, so you often find duplicated entities, JSON blobs where relations belong, missing foreign keys, and no indexes beyond the primary key.
Green: entities map cleanly to your business (users, accounts, orders, subscriptions), relations are enforced, and migrations exist. Red: the same fact is stored in three places, or you cannot answer "what does one row mean" for core tables. Schema problems can often be fixed in place with careful migrations, as covered in database schema migrations with AI safeguards, but a model that is wrong at the root pushes you toward a rebuild.
2. Are authentication and authorization trustworthy?
Security is the signal that overrides the others. Check whether access control is enforced on the server or only hidden in the UI, whether row-level rules actually exist, and whether secrets ever reached the client bundle. Open the network tab, replay a request with another user's ID, and see what comes back.
If authorization is scattered across components and every endpoint decides for itself, patching it means touching the entire app, which is a rebuild of that layer whatever you call it. For Firebase-backed apps, Firestore security rules are a good litmus test: if they are open or absent, treat security as the first layer to replace.
3. Can you change one thing without breaking three others?
Pick a small, realistic change, such as renaming a field or adding a filter to one list, and time it. In a healthy codebase the change touches one or two files. In a tangled one it ripples through components that share state by accident, copied logic, and hooks that depend on render order.
Ripple is a sign of structure, not necessarily of a doomed app. State sprawl in React, for example, is fixable in steps, as shown in refactoring vibe-coded state. Count it as a red flag only if the ripple continues after you have isolated one module.
4. Is there any test safety net?
Refactoring without tests is rewriting with extra steps, because you cannot prove behavior stayed the same. Count what exists: unit tests, end-to-end flows, even a manual checklist. If there are none, the first job of a refactor is to pin down current behavior with a handful of end-to-end tests around the money paths (signup, checkout, the core action). See deterministic E2E testing rules for AI code.
If you cannot write those tests because the app behaves differently on each run, or the flows are unreachable without manual database edits, that is a strong rebuild signal.
5. Does the stack match where the product is going?
Prototype tools choose for speed: client-heavy SPAs, backend-as-a-service defaults, and whatever libraries the model knew best. That is fine until requirements change. You need real background jobs, native mobile apps, strict compliance, or heavy server logic, and the current stack fights you.
Ask what the next six months of features require, and whether the current architecture can host them. Moving a React web app toward the App Router is a refactor (porting to the Next.js App Router). Moving from a no-code backend to your own services with custom auth is a rebuild of that layer.
6. Does anyone understand the code well enough to own it?
A codebase is an asset only if some human can explain how it works. If the original author was a prompt and the history is a thousand "fix" commits, you may have no owner at all. Reading unfamiliar code is cheaper than most people fear, but only when it has a consistent shape.
Try this: ask a developer who has not seen the project to trace one request from the button click to the database write and back. If they finish in an hour, you can refactor. If they get lost in three different data-fetching patterns and two competing auth flows, the cost of understanding approaches the cost of writing it again.
Run a timeboxed refactoring spike before you decide
Opinions are cheap, so measure. Spend two to three days on a spike with a clear question: can we make the single worst module clean, tested, and understood in this time?
# 1. Pin behavior: write 3-5 end-to-end tests for the critical flows
npx playwright test --project=chromium
# 2. Find the hotspots: files that change most and break most
git log --since="60 days ago" --name-only --pretty=format: \
| sort | uniq -c | sort -rn | head -15
# 3. Check dependency and type health
npx tsc --noEmit
npm audit --omit=dev
Pick the module from the hotspot list that hurts most, refactor it behind the tests, and note how it went. If the spike succeeded, you have a method you can repeat. If it exposed deeper problems, such as a missing schema constraint or logic that cannot be isolated, you have the evidence for a rebuild, and you found it for the price of a few days, not a few months.
If you rebuild, protect what the old app knows
The biggest hidden cost of a rebuild is losing behavior nobody wrote down. The old app contains business rules, edge-case fixes, and data quirks that only exist in code. Before you start:
- Write down every user-facing flow and the rules behind it, using the running app as the source of truth.
- Export and profile the real data, because production rows violate every assumption you made.
- Keep the old app live and cut over module by module, with a rollback path.
- Reuse what is worth reusing: design assets, copy, API contracts, and the tests you wrote for the spike.
Do not rebuild with the same prompt-and-pray workflow that produced the first version. Define the schema and API contracts first, enforce types end to end, and use the AI as a fast pair programmer inside those boundaries, as in strict TypeScript for inherited AI apps.
Decision summary
| Signal | Points to refactor | Points to rebuild |
|---|---|---|
| 1. Data model | Sound, maybe missing indexes | Duplicated or meaningless entities |
| 2. Auth and access | Enforced on the server | UI-only checks, no row-level rules |
| 3. Change ripple | Ripple stops once a module is isolated | Ripple continues everywhere |
| 4. Tests | Flows can be pinned with a few E2E tests | App is non-deterministic or untestable |
| 5. Stack fit | Stack supports the roadmap | Stack blocks core upcoming features |
| 6. Ownership | New developer traces a request in an hour | Nobody can explain the flow |
FAQ
Is it cheaper to refactor or rebuild a vibe-coded app?
Refactoring is usually cheaper when the data model and security are sound, because you keep working behavior and ship improvements continuously. A rebuild costs more upfront and is justified when repair would touch most of the app anyway. Run a two to three day spike to replace guesswork with a measured estimate.
How do I know my vibe-coded app is beyond repair?
The clearest signs are a broken data model, missing server-side authorization, and behavior that cannot be pinned with tests. If a new developer cannot trace a single request end to end, ownership cost also approaches rebuild cost. One signal is a warning; four or more is a decision.
Can AI tools do the refactor for me?
They can do much of the mechanical work, such as extracting components, renaming, and converting to stricter types, but only inside a safety net of tests and review. Without that net, an agent can restructure code and silently change behavior, which is exactly the risk a refactor is meant to avoid.
Should I stop shipping features during a refactor?
Not entirely. Freeze changes to the module being refactored, keep shipping elsewhere, and merge in small steps. A long-lived "cleanup branch" that diverges from main is the usual way refactors fail.
Next step
If you have a vibe-coded app and want a second opinion on refactor vs rebuild, a short audit of the schema, auth, and one critical flow is usually enough to give a confident answer. You can reach me through gramowski.dev.