Replit Agent code messy: how to clean up an Agent-built codebase without breaking it
Agent edits what each prompt asks for, so after weeks of chat a Replit app collects duplicate components, dead routes and a database schema out of step with the code. Clean it in small reviewed steps: write real rules into replit.md, plan each refactor in Plan mode, commit to GitHub before every change, and read the migration SQL before it reaches production.
Symptom
The app works, mostly. But every change now costs more than the last:
- The same button, form or fetch helper exists in three versions.
- Fixing a bug on one page breaks something on another.
- Agent goes in circles on a task it handled easily a month ago.
- Publishing stops at the database step:
That last one is the mess showing up in the data, which is where it gets expensive.
Why it happens
Each prompt is local
Agent changes what the prompt describes. It reads replit.md for project conventions, but the file Agent creates at the start is generic. Unless someone writes the real rules into it, every session starts without them. So Agent builds a second date picker because it didn't know about the first.
Long chats and big asks
Replit's Agent help page gives the same fix for loops: break large tasks into one goal per message and use Plan mode to scope the work first. It also advises starting a new Agent chat when you switch tasks.
Rollbacks split code from data
Rolling back to a checkpoint restores files, packages and config. It leaves the development database alone unless you tick Database under Additional rollback options. Roll back code a few times and the schema no longer matches the code that uses it.
The databases drift
At publish, Replit compares the real development and production databases, not your schema file. A column you added by hand in production gets proposed for deletion on the next publish. A rename answered with No, create new column drops the old column's data. Any drizzle-kit push hidden in a build or start script runs outside that review on every publish.
The fix
- Snapshot everything first. Connect GitHub in the Git pane and push, then tag the starting point:
git push -u origin main
git tag pre-cleanup && git push origin pre-cleanupReplit also keeps a gitsafe-backup remote of your history, but your own copy on GitHub is the one you control.
- Rewrite
replit.mdwith real rules. It must sit in the project root. Keep it short and specific, and use your project's actual paths:
# Project rules
## Structure
- Pages: client/src/pages, one file per route.
- Shared UI: client/src/components/ui. Reuse before creating anything new.
- API routes: server/routes, one file per resource.
- Database schema: shared/schema.ts only.
## Rules
- Every /api route checks the signed-in user on the server.
- Never change the schema from build or start scripts.
- Ask before adding a package.
- Before editing, list the files you will change and wait for approval.- Map the mess before touching it. In the Shell:
# Largest files first: tangles usually live here
git ls-files "*.ts" "*.tsx" | grep -v node_modules | xargs wc -l | sort -rn | head -20
# Type errors Agent has been working around
npx tsc --noEmit
# Unused files, exports and dependencies (may need a config file)
npx knipThen read the biggest files yourself. What I look for first:
- The same fetch or validation logic copied into several components.
- API routes that never check who is calling.
- Components several hundred lines long that mix data loading, layout and business rules.
- Hard-coded prices, emails or URLs that belong in config.
- Files nothing imports any more.
Write the findings down as a list of small jobs: merge the three buttons, delete the dead routes, move all fetches into one API client. Order them by risk, with anything touching sign-in, payments or the schema last.
- Put a test around anything you'll touch. Agent's App Testing clicks through the app in a real browser, and works for full-stack JavaScript and Streamlit web apps in Power and Max modes. Agent decides when to run it, so it isn't a test suite you control. Add a few tests of your own that pin down behaviour before a refactor:
// tests/projects.test.ts (export the Express app separately from app.listen)
import request from "supertest";
import { describe, it, expect } from "vitest";
import { app } from "../server/app";
describe("projects API", () => {
it("refuses signed-out requests", async () => {
const res = await request(app).get("/api/projects/1");
expect(res.status).toBe(401);
});
});-
One refactor per task, planned first. Turn on Plan, describe one job from your list, and read the plan. Choose Build in background to run it as a separate task. By default background tasks wait for you to review and apply their changes, which is what you want here. Run the tests, commit, then move to the next job.
-
Bring the schema back into line. Ask Agent to compare the development schema with production through its read-only view, without changing anything. When you publish, read the generated SQL, answer every rename question deliberately, and use Create preview deploy for anything that touches tables with data. Only choose Copy your development database schema & data to production if production holds nothing worth keeping, because it replaces the data.
-
Roll back with care. If a step goes wrong, roll back to the checkpoint before it, and include the database if that step changed the schema.
How to prevent it
- Start a new Agent chat for each task, and keep using Plan mode for anything bigger than a small fix.
- Update
replit.mdwhenever you make a decision Agent should remember. - For patterns you repeat, such as a new CRUD screen, write an Agent Skill in
/.agents/skillsso every session builds it the same way. - Commit and push before every Agent task, so each change has a clean diff.
When to get help
Some codebases are past a tidy-up. Read refactor or rebuild a vibe-coded app before you spend weeks on it, and handing over AI-generated code if a developer is about to take over. Messy code and broken sign-in often travel together, so check Replit auth not working as well. The guide to fixing vibe-coded apps puts all of this in order.
The free vibe-code health check gives a quick read. If you want it untangled properly, that's what a Rescue Sprint is for.
- Replit docs: replit.md, checked 10 November 2026
- Replit docs: Checkpoints and Rollbacks, checked 10 November 2026
- Replit docs: Plan Mode, checked 10 November 2026
- Replit docs: Agent and AI help, checked 10 November 2026
- Replit docs: App Testing, checked 10 November 2026
- Replit docs: Agent Skills, checked 10 November 2026
- Replit docs: How Publish updates your production database, checked 10 November 2026
- Replit docs: Development and production databases, checked 10 November 2026
- Replit docs: Git disaster recovery, checked 10 November 2026
The vibe-code rescue checklist, as a PDF
About 40 checks across auth, data, payments, errors, mobile and secrets, on two pages.
Questions founders ask
Can I just ask Replit Agent to refactor the whole app?
You can, but one giant prompt is how loops and surprise breakages happen. Replit's own advice is one goal per message and Plan mode for scoping. Refactor one area at a time and test after each step.
Does rolling back a checkpoint undo database changes too?
Not by default. Replit rollbacks restore code and configuration, and only restore the development database if you select Database under Additional rollback options. The production database is never rolled back this way.
Should I refactor or rebuild a messy Replit app?
If the data model is sound and the core flows work, refactor. If the schema is wrong at the root and every feature works around it, a rebuild of the core is often cheaper.

Ant
Product designer who builds MVPs, based in Nottingham. 10+ years designing digital products, and the only person at BlackFig. More about me