Engineering · March 2026
How to Fix a Vibe-Coded App: From AI Prototype to Production
"Vibe coding" — using AI tools like Cursor, Copilot, or ChatGPT to rapidly generate an application by describing what you want — has made it possible for anyone to build a working prototype in hours. But there is a gap between "it works on my machine" and "it is ready for real users." This guide covers the most common problems with vibe-coded apps and how to fix them systematically.
What Is Vibe Coding and Why Does It Break?
The term "vibe coding" was coined to describe a workflow where you give an AI model high-level instructions and accept the generated code without deeply reviewing it. The AI fills in implementation details based on patterns from its training data. This works remarkably well for getting something functional fast.
The problem is that AI models optimise for plausible-looking code that compiles, not for production readiness. They do not understand your specific business requirements, security constraints, scale requirements, or edge cases. The result is code that demos well but fails under real-world conditions.
The Most Common Problems with AI-Generated Code
1. No Error Handling
AI-generated code typically follows the "happy path" — it works when everything goes right but crashes or behaves unpredictably when things go wrong. API calls without try/catch blocks, missing null checks, and unhandled promise rejections are extremely common. In production, these turn into blank screens, cryptic error messages, or silent data corruption.
2. Security Vulnerabilities
This is the most dangerous category. Vibe-coded apps routinely contain:
- Exposed API keys — hardcoded in the frontend or committed to version control.
- Missing authentication checks — API endpoints that anyone can access without logging in.
- SQL injection — string-concatenated queries instead of parameterised statements.
- No input validation — accepting any data from users without sanitisation.
- Insecure direct object references — accessing other users' data by changing an ID in the URL.
3. Performance Problems
AI models often generate the most straightforward implementation, not the most efficient one. Common performance issues include N+1 database queries (fetching related records one at a time inside a loop), loading entire datasets into memory instead of paginating, missing database indexes, and redundant re-renders in React components.
4. No Test Coverage
AI can write tests if you ask, but vibe-coded apps are typically built in a rapid "just make it work" mode where testing is skipped entirely. Without tests, every change becomes a gamble — you have no way to know whether fixing one thing broke something else.
5. Architectural Mess
When you build by describing features one at a time, the resulting codebase often has no coherent architecture. Business logic is mixed into UI components, data fetching is duplicated across files, state management is inconsistent, and there is no clear separation of concerns. This makes the codebase increasingly difficult to modify over time.
How to Assess the Damage
Before you start fixing things, take stock of what you have. At ULB Media, we run a structured code audit for every vibe-coded project we inherit. Here is a simplified version you can follow:
- Run a linter — set up ESLint (for JavaScript/TypeScript) with a strict config. The number of warnings gives you a rough quality score.
- Check for secrets — use a tool like gitleaks or trufflehog to scan for API keys in the codebase and git history.
- Review authentication — manually trace the flow from login to protected routes. Can you access data without a valid session?
- Check database queries — look for raw SQL strings, missing indexes, and queries inside loops.
- Test edge cases — what happens with empty inputs, very long strings, special characters, or concurrent users?
Refactor vs. Rewrite: Making the Call
The eternal question. Here is a practical framework:
Refactor when the core architecture is sound but the details are sloppy. If the app uses a reasonable tech stack, has a logical file structure, and the main user flows work correctly, you can systematically improve it by adding error handling, tests, security checks, and performance optimisations.
Rewrite when the architecture itself is the problem. If business logic is deeply entangled with UI rendering, the data model is fundamentally wrong, or the tech stack cannot support your requirements, a targeted rewrite (not necessarily from scratch) may be more efficient than trying to untangle the mess.
A middle path that works well: keep the working frontend as a reference (or even reuse it), but rewrite the backend and data layer with proper architecture. This preserves the AI's UI work while rebuilding the critical infrastructure.
Step-by-Step Refactoring Strategy
Phase 1: Secure It (Day 1)
Security issues are urgent. Before anything else:
- Move all API keys and secrets to environment variables.
- Rotate any keys that were exposed in the codebase or git history.
- Add authentication middleware to all protected API routes.
- Add input validation and sanitisation on all user inputs.
- Switch to parameterised database queries.
Phase 2: Stabilise It (Week 1)
Add error handling so the app fails gracefully:
- Wrap API calls in try/catch with user-friendly error messages.
- Add loading and error states to every data-fetching component.
- Set up error tracking (Sentry, LogRocket, or similar).
- Add a global error boundary in React.
Phase 3: Test It (Week 2–3)
You do not need 100% coverage immediately. Start with the most critical paths:
- Write integration tests for authentication flows.
- Test payment and billing logic if applicable.
- Add unit tests for business logic functions.
- Set up CI to run tests on every pull request.
Phase 4: Optimise It (Week 3–4)
With the app secure, stable, and tested, address performance:
- Add database indexes for frequently queried columns.
- Replace N+1 queries with joins or batch fetches.
- Implement pagination for list endpoints.
- Add caching where appropriate (Redis, CDN, or in-memory).
- Profile React renders and memoise expensive computations.
Using AI to Fix AI-Generated Code
There is an irony here, but it works. AI tools are excellent at refactoring code when you give them specific, bounded tasks. Instead of "build me an app," use prompts like:
- "Add comprehensive error handling to this API route."
- "Write unit tests for this function, including edge cases."
- "Refactor this component to separate data fetching from rendering."
- "Review this code for security vulnerabilities."
The difference is human oversight. When a skilled developer uses AI as a tool rather than a black box, the output quality is dramatically higher. At ULB Media, our engineers use AI assistants daily — but every line of generated code is reviewed, tested, and understood before it ships to production.
When to Bring in Professional Help
Vibe coding is a powerful prototyping tool. But if your app handles sensitive data, processes payments, serves a growing user base, or is critical to your business operations, having experienced engineers review and harden the codebase is not optional — it is a business requirement.
The cost of fixing a security breach or recovering from data loss far exceeds the cost of doing it right. Many of ULB Media's clients come to us with a vibe-coded MVP that proved market demand. We take that validated prototype and rebuild the critical parts to production standards — keeping what works and replacing what does not.
Need help fixing a vibe-coded app?
ULB Media specialises in taking AI-generated prototypes and transforming them into secure, scalable, production-ready applications.
Get in Touch