~/oybek.dev
Book a call
insights
ProcessJune 14, 2026· 7 min read

How to rescue a vibe-coded app for production

You rarely need a rewrite — you need the boring production layer the AI skipped. Here are the five things every vibe-coded app gets wrong, and the order I fix them.

You can rescue a vibe-coded app for production far more often than you can justify a rewrite. The demo works. The buttons click. A friend tried it and was impressed. Then someone real signs up, the first invoice fires, and the thing falls over. I get these handoffs regularly: a founder built a working prototype with an AI coding tool over a weekend, raised a little money or landed a first customer, and now needs it to survive contact with the public internet. The code is rarely the problem. What's missing is the boring production layer the AI quietly skipped — and putting that layer in is a senior-engineer job, not another prompt.

Why the demo lies

A demo proves one path works once, for one person, on one machine, with no money and no attacker involved. Production is the opposite of all four. It runs the unhappy paths, for strangers, on infrastructure you don't control, with real payments and real adversaries poking at every endpoint.

AI coding tools are very good at the demo and structurally blind to the rest. They optimise for "make the screen do the thing I asked," because that's what you can see and approve in the chat. Nobody prompts "and please rotate the leaked API key, add a database index, and verify the Stripe webhook signature" — so none of it gets built. The model isn't lazy. It gives you exactly what you asked for, and you asked for a demo. That gap stays invisible until traffic finds it, which is why the rescue work starts by naming it precisely.

Abstract neon-green circuit traces forming a bright complete path across a near-black grid, with thin broken traces fading out around it
The demo lights up one path. Production is everything around it.

The five things every vibe-coded app gets wrong

Across the handoffs I take on, the same five holes show up almost every time. This is the spine I check first, and it's the same list I work through on the vibe-coding rescue service.

Auth: tokens in localStorage

The AI ships a login that works, then stores the session token in localStorage because it's the path of least resistance. Any cross-site script on your page can now read it, and a stolen token is a stolen account. Sessions belong in httpOnly cookies with sensible expiry and a real logout that invalidates server-side. This is the single most common hole, and the most damaging.

Secrets: API keys in the client bundle

"It works on my machine" usually means the keys are hard-coded somewhere convenient — and convenient often means the browser bundle. Your Stripe secret key, your database URL, your third-party tokens get shipped to every visitor's dev tools. The fix is real environment separation: secrets stay server-side, the leaked ones get rotated immediately, and nothing sensitive crosses to the client.

Data: no indexes and N+1 queries

The database works fine with the twelve rows you tested on. Then a list view that loads each related record in its own query meets a thousand rows, and the page takes nine seconds. No indexes on the columns you filter and sort by, queries inside loops, no pagination. None of this shows in the demo because the demo has no data. All of it shows the week you get users.

Payments: unverified webhooks

The checkout flow looks done — money moves, the success page renders. But the webhook that confirms payment doesn't verify the signature, so anyone who finds the endpoint can POST a fake "paid" event and unlock the product for free. Worse, the app often grants access on the client redirect instead of the verified server event, so a closed browser tab means a paid order that never provisions. Payments are where unverified trust turns directly into lost money.

Deploys: works on my machine

There's no staging environment, no migrations, no rollback. Deploying means SSHing in and pulling main, or clicking a button with no way back if it breaks. The first bad deploy takes the whole thing down with no undo. Before I touch anything else, this is what I fix first — because you can't safely repair the other four without somewhere to test and a way to roll back.

Five neon-green nodes on a near-black grid connected by a single circuit spine, one node pulsing brighter than the rest
The same five holes, almost every time: auth, secrets, data, payments, deploys.

Rescue, not rebuild — the order I fix things

The instinct when you inherit messy code is to throw it out and start clean. That instinct is usually wrong and always expensive. The working app already encodes real product decisions and real user feedback. My job is to make it safe, not to make it mine. So I work in a fixed order, safety-first:

  1. Version control and staging. Get the code into Git with a clean history, stand up a staging environment that mirrors production, and add migrations and a rollback path. Now every later change is reversible. Nothing else is safe without this.
  2. Secure. Move secrets server-side and rotate anything that leaked, fix auth and session storage, lock down the payment webhooks. Stop the bleeding before optimising anything.
  3. Harden. Add the database indexes, kill the N+1 queries, add pagination, add input validation and rate limiting, wire up error tracking so you find out about failures before your users tweet them.

Whether the stack is Laravel on the API or Next.js on the frontend, the order doesn't change — only the specifics do. This is the same triage I described in the 48-hour scope: resolve the unknowns first, then the work becomes arithmetic.

You rarely need a rewrite. You need the boring production layer the AI skipped — and that's a senior call, not a prompt.

When it actually is faster to rebuild

I'd be lying if I said rescue always wins. Sometimes the honest answer is to rebuild, and I'll tell you when it is.

Rebuild when the data model is fundamentally wrong in a way that every feature depends on — fixing the foundation means rewriting everything above it anyway. Rebuild when the AI generated thousands of lines of duplicated, untyped spaghetti with no seams to grab, where every change risks three regressions. Rebuild when the framework choice can't support where the product needs to go, or when there are so many security holes that auditing them costs more than starting clean.

The test I use: can I make the next ten changes safely without fear? If yes, rescue. If every change is a coin flip, the code is a liability, not an asset, and a focused rewrite of the core — keeping the product decisions, discarding the implementation — is the cheaper path. The point is that this is a deliberate judgement, made by someone who's shipped both, not a reflex.

What "production-ready" actually means

Production-ready isn't a feeling, it's a checklist. Secrets are server-side and rotated. Auth uses secure cookies and real session invalidation. The database has indexes, no N+1 queries, and pagination. Payment webhooks verify signatures and access is granted on verified server events. There's a staging environment, migrations, and rollback. Errors are tracked and logged. Inputs are validated and endpoints are rate-limited. Backups exist and you've tested restoring one.

A neon-green checklist of short horizontal traces on a near-black grid, each line terminating in a small filled node
Production-ready is a checklist, not a vibe.

None of that is glamorous and none of it shows in a demo. That's exactly why the AI skipped it and exactly why it needs a senior engineer. If you want a second pair of hands that's done this on real production systems, that's the fractional CTO and vibe-coding rescue work I do — and if you're an agency that needs it done quietly under your name, that's white-label senior dev work.

FAQ

Is vibe coding bad?

No. Vibe coding is a genuinely good way to get from idea to working prototype fast, and I use AI tools daily. The mistake is treating the prototype as finished. It proves the product is worth building — it doesn't make it safe to put real users and real money in front of. Use it to start, then bring in someone to add the production layer before you launch.

Should I rebuild or fix my AI-built app?

Fix it, in most cases. The working app already holds real product decisions, so throwing it out is expensive and usually unnecessary. Rebuild only when the data model is fundamentally wrong, the code has no seams to safely change, or the security holes cost more to audit than to replace. The deciding question is whether you can make the next ten changes without fear.

What breaks first when an AI-built app hits production?

Almost always one of five things: session tokens stored in `localStorage`, API keys shipped in the client bundle, missing database indexes and N+1 queries, payment webhooks that don't verify signatures, and the absence of staging or rollback. The demo hides all five because it has no real users, no real data, and no attackers.

Can an AI-built MVP be made production-ready?

Yes, and that's usually the right move. The path is to add version control and staging first, then secure auth, secrets, and payments, then harden the data layer and deploys. The product code you already have is the asset. What's missing is the boring infrastructure work around it, and that can be added without starting over.

How long does it take to rescue a vibe-coded app?

It depends on the size of the holes, but the security-critical fixes — secrets, auth, payment verification — are usually days, not weeks, because the list is predictable. Hardening data and deploys takes a bit longer. I always start with a short audit so the timeline and cost are known before any work begins, rather than open-ended.