All articles
11 min read

Your vibe-coded app works. Here is what breaks when real users arrive.

The short answer

AI coding tools produce working demos, not production systems. The same seven problems appear in almost every generated codebase: authorization enforced in the browser, secrets in the client bundle, a schema with no constraints, no migrations, no backups, unbounded queries, and no deployment path. None of them show up in a demo. All of them show up with real users.

Why the demo never reveals the problem

A demo is one person, clicking the happy path, on a fast connection, with ten rows of data they created themselves. Every failure mode below needs at least one of the four things a demo does not have: a second concurrent user, an adversarial user, real data volume, or a second deployment.

This is not a criticism of the tools. Lovable, Bolt, Replit, v0 and Cursor are genuinely good at producing a working artefact fast, and a founder who validates demand with one is doing something smarter than a founder who spends six months on architecture nobody wanted. The problem is that the artefact and a production system look identical from the outside, so nothing warns you when you cross from one to the other.

The crossing point is your first real user. Everything below is what we find on the other side of it.

1. Authorization that only exists in the browser

The most common and most expensive failure. The generated app hides the admin button when the logged-in user is not an admin, and stops there. The API endpoint behind that button checks nothing. Anyone who opens the network tab, copies the request and changes one field in it can do whatever the admin can do.

Hiding a control is a user-interface decision. Refusing a request is a security decision. AI tools reliably produce the first and frequently skip the second, because from inside a single-user demo they are indistinguishable.

The fix is not a patch. Authorization has to be enforced in one place on the server, on every request, derived from the session rather than from anything the client sent. Retrofitting that means touching every endpoint, which is why it is the first thing we do in a rescue and why doing it later costs several times more.

2. Secrets that shipped to the browser

API keys for payment providers, email services, storage buckets and AI models end up in client-side code because that is where the generated call was made from. Anyone can read them. Bundlers do not hide them; view-source and a search for the provider prefix finds them in seconds.

Two things follow. First, the key has to be rotated, because it must be assumed compromised from the moment it shipped. Second, the call has to move to a server route, which usually means restructuring the feature that made it rather than moving one line.

The bill for this one is not the engineering time. It is the provider usage somebody else runs up on your account before you notice.

3. A database schema with no constraints

Generated schemas tend to be a set of tables with the right column names and almost none of the rules that keep data honest: no foreign keys, no unique constraints, no not-null where it matters, no check constraints, and no indexes beyond primary keys.

For the first month this is invisible. Then you find two accounts with the same email address, an order pointing at a customer who no longer exists, a null in a field the code assumes is always present, and a listing page that takes nine seconds because there is no index on the column it filters by.

Every one of those is a data-correctness bug that the database itself could have refused to allow. Once bad rows exist, fixing the schema means cleaning the data first, which is why this gets worse every week you leave it.

4. No migrations, so the schema exists in exactly one place

Ask how your database gets from its current shape to its next shape and the answer is usually that someone edits it in a web console. That means there is no record of what changed, no way to reproduce the database on another machine, and no way to reverse a change that went wrong.

It also means you cannot have a staging environment, because a staging environment is by definition a second copy of your schema. Which leads directly to the next problem.

5. One environment, which is production

Generated projects deploy to a single place. There is no staging, so every change is tested by your customers. There is no rollback, so a bad change is fixed by making another change under pressure. There is often no version history outside the tool that generated it.

The cost here is not a single incident. It is that the fear of breaking production makes you stop shipping, which is the thing the AI tool was supposed to have made easy.

6. No backups, or backups nobody has restored

Most founders assume their database host backs things up. Many hosts do, on a schedule and a retention window you have not read. Almost nobody has tried a restore.

An untested backup is a belief, not a backup. The question worth answering today is not whether backups exist but how many minutes of data you would lose and how many hours the restore would take, and whether you have ever proved either number.

7. Queries with no ceiling

Generated code fetches everything and filters in the application: every order, every message, every row, then a slice for the page you are showing. With fifty rows it is instant. With fifty thousand it takes the server down, and it takes it down for every user at once rather than just the one who triggered it.

The same pattern appears in exports, dashboards and search. The fix is pagination, indexes, and moving the filter into the database — routine work, but work that touches every list in the product.

What this costs to put right

Roughly, and assuming the product itself is worth keeping, which it usually is. These are engineering-effort bands rather than quotes; the variable is how many features exist, not how complicated any one of them is.

ProblemTypical effortWhat it costs to delay
Server-side authorization1–2 weeksA data breach involving your customers' records
Rotating and moving secrets2–4 daysProvider bills run up on your account
Schema constraints and indexes1–2 weeksGrows weekly as bad rows accumulate
Migrations and staging3–5 daysBlocks every other fix on this list
Backups, proven by restore1–2 daysTotal loss, once
Pagination and query limits3–5 daysOutages that scale with your success

Doing them in that order matters. Authorization first, because everything else is repairable and a breach is not. Migrations and staging early, because they are what make the remaining work safe to do on a live product.

What we do not recommend

Starting over. The instinct when an engineer sees generated code is to rewrite it, and it is usually wrong. The product logic encodes decisions you made while talking to real users, and the interface has been validated by people using it. Throwing that away to gain a codebase an engineer finds tidier is an expensive aesthetic preference.

What actually needs replacing is the layer underneath: authorization, schema, deployment, backups. That work can be done while the product stays live, one piece at a time, with your users noticing nothing. A rewrite means months with no new features and a real chance the second version never ships.

We recommend a full rewrite in perhaps one case in ten, and when we do, we show the specific evidence before anyone commits to it.

Where to start this week

  1. 01Run the network-tab test in section one. It takes five minutes and it is the finding that cannot wait.
  2. 02Search your frontend bundle for your provider key prefixes. If you find one, rotate it today, before you fix anything.
  3. 03Ask your database host what your backup retention is, then restore one into a scratch database and time it.
  4. 04Open the slowest list in your product and check whether it has a limit clause. Then check whether the column it sorts by has an index.
  5. 05Write down how you would undo your last deployment. If there is no answer, that is the fourth thing to fix.

That list is deliberately something you can do without hiring anyone. If it turns up more than you want to handle, an assessment is the cheapest next step: a few days of reading, running and attacking the codebase, and a written report you own and can hand to any developer, including one who is not us.

Related questions

Is code generated by AI tools bad code?
No. It is usually reasonable code that is missing the parts a demo never needs: server-side authorization, schema constraints, migrations, environments and backups. The problem is not quality inside a file, it is that the system around the files was never built.
Can you fix this without taking my product offline?
Yes, and that is the normal case. Authorization, schema, deployment and backups are replaced underneath a running product, one piece at a time. Users see nothing. A rewrite is the approach that requires downtime, which is one of several reasons we avoid it.
How long does a vibe-coding rescue take?
A typical rescue runs three to six weeks after a three-to-five day assessment, depending on how many features exist. Security work lands in the first fortnight because a breach is the only item on the list that cannot be undone.
Do I have to keep working with you after the assessment?
No. The assessment report is yours whether or not you continue, and it is written so that any competent developer can act on it. Some clients use it to brief their existing developer, which is a perfectly good outcome.

Two ways to start, both of them cheap.

Book a call and talk it through, or write the problem down and send it — whichever you would actually do today. Either way you get a reply from an engineer within one business day, and an honest answer about whether we are a fit.

Not ready for either? A $600 consulting session buys one straight answer with no obligation to hire us.

Rev. 01Book a call