Vibe Coding Works on Day 1. Here's What Breaks by Day 30.
AI-generated code ships fast, then stops scaling. Why vibe-coded apps break in production, the seven failures we see most, and how to prevent them.
There is a meme going around that engineers keep sending each other. Day 1 of vibe coding: a person lying in a sunlit meadow, laughing, holding a happy baby above their head. Day 30 of vibe coding: same meadow, same pose, except the meadow is on fire, the baby has teeth, and the labels floating around the wreckage read No auth, Tech debt, Token limits, Spaghetti code, Exposed API keys.
It keeps getting sent because it keeps being true. We run Patchlane, the arm of this company that takes over AI-generated codebases after something has gone wrong, and the meme is a fairly accurate intake form.
But the part everyone skips is the top panel. Day 1 is not a joke. Day 1 is real, and it is genuinely good. Understanding why is the only way to understand what goes wrong later.
Day 1 is real. Don’t let anyone tell you otherwise.
An experienced engineer can now describe an application in a paragraph and have a working version — routes, database, styling, deployment — inside an afternoon. Not a mockup. A thing you can log into.
That is not a parlour trick, and the people dismissing it as one are wrong. A whole class of work that used to cost a fortnight now costs an afternoon: the CRUD screens, the admin panel, the third settings page, the migration script, the boilerplate that no senior engineer ever wanted to write anyway. Founders can validate an idea before spending a budget on it. Small teams punch far above their headcount.
We use AI to write code every single day, and we would not go back.
So when a founder tells us their team built the first version in a week and the investors loved the demo, we believe them. That week happened. It was real work and it produced real value.
The problem is that the week worked so well that nobody asked why it worked.
Day 30: the same process, thirty times the surface area
Here is the uncomfortable thing about Day 1. It worked because the app was small enough to fit in one head — and, more importantly, in one context window.
At five hundred lines, every decision is local. There is only one place users are fetched from, so it does not matter what you call it. There is one form, so it does not matter how validation is structured. There is one deployment, so configuration can live wherever it landed. You can hold the entire system in working memory, which means you can prompt your way through it, and every answer you get back is coherent with everything else, because everything else is four files.
At forty thousand lines, none of that is true. And here is what nobody is told: the process did not change. The same prompt-and-accept loop that was ideal at five hundred lines is still being run at forty thousand. It was never upgraded, because it never visibly failed. It just quietly stopped being sufficient somewhere around week two, and the bill arrived in week five.
That is the actual mechanism behind the burning meadow. Not bad code. An excellent process, run far past the size it was designed for.
The seven things that actually break
These are the findings that show up, in some combination, in nearly every AI-generated codebase we audit. None of them is exotic. All of them are symptoms of the same missing thing.
1. Authentication exists. Authorization doesn’t.
Login works. It nearly always works, because “add authentication” is a well-defined problem with excellent documentation, and AI handles it cleanly.
What is missing is the second half. Authentication asks are you logged in. Authorization asks are you allowed to touch this particular row. The generated endpoint checks the first and skips the second, so GET /api/invoices/1043 returns invoice 1043 to any valid session — including the session belonging to a different customer.
Nobody notices during development, because in development there is one user: you. It surfaces the first week you have two customers, and it surfaces as a data breach rather than a bug report.
2. Keys that live in the browser
Somewhere around the time the payment provider or the email service was wired up, a key went into a variable that gets bundled into the client. Sometimes it is prefixed in a way that explicitly marks it public. Sometimes the service key was used because the anon key threw a permissions error and the fastest way past a permissions error is a key with more permissions.
The application works perfectly. The key is also in a JavaScript file that anyone can open in their browser’s network tab.
3. A database with no migration story
The schema was changed by asking for a change, and the change was applied by hand to the live database. Repeat twenty times over six weeks.
There is now no record of how the current schema came to exist, no way to recreate it, and no way to stand up a staging environment that matches production. The database is the documentation, and it exists in exactly one copy. Everyone on the team knows not to touch it, which is another way of saying the product cannot change.
4. The same logic, written four times
This one is subtle, and it is the purest expression of the underlying problem.
Each prompt produces a locally excellent answer. “Fetch the user’s active subscription” gets a clean, correct function. The trouble is that this happened in week one, then again in week three when a different screen needed the same thing, then in week five in a slightly different shape, then in week seven with a bug fix applied to only one of the four.
No individual answer was wrong. There was simply nobody with a view wide enough to say we already have this. Now a change to billing rules means finding all four, and nobody knows there are four.
5. Context-window amnesia
The assistant does not remember the architectural decision it made three weeks ago, because that conversation is gone. It re-decides, reasonably and differently, every time.
So the codebase contains two date libraries, three error-handling conventions, two ways of talking to the database, and two state-management approaches — each one defensible in isolation, and collectively a codebase that reads like it was written by four people who never met. Which is precisely what happened.
6. Tests that were never asked for
Nobody prompts for tests. Tests slow down the demo, and the demo was the point.
This is survivable at Day 1 and disqualifying at Day 30, because it removes the only mechanism that lets you change a large system safely. Without tests, every change is a gamble, so the team stops making changes, so the product stops moving. The codebase is not broken. It is frozen, which for a company is worse.
7. Routes that go nowhere
The 404 in the meme is not decorative. Features get half-built when a prompt goes sideways and the conversation moves on. A link points at a page that was renamed. An endpoint was replaced but the old one still answers. The build passes, because nothing here is a compile error.
Why it compounds instead of just accumulating
Normal technical debt accumulates. You take a shortcut, you know you took it, someone writes a ticket, and it sits in a backlog looking at you.
Vibe-coded debt compounds, for one reason: it is invisible at the moment of creation. There is no shortcut being knowingly taken. Every step produces working, plausible, well-formatted code that does the thing you asked. The system degrades while every individual interaction looks like a success.
By the time it is visible — the first outage, the first security disclosure, the first feature that takes three weeks instead of three days — it is no longer in one place. It is distributed across every file, because it was never a decision. It was the absence of one.
And that is the real finding. The problem was never the code. The missing artifact was the thinking that should have preceded it. AI will happily write any system you describe. It will not tell you that you have not decided what you are building.
The part nobody wants to say out loud: it went to production anyway
Here is where this stops being an engineering essay and becomes a business one.
None of the above would matter much if these apps stayed as prototypes. They do not. The demo worked, the investors liked it, a customer asked when they could start, and the thing that was built to answer is this idea worth pursuing is now the thing that holds paying customers’ data.
That transition — prototype to production — used to have friction. It used to involve an engineer saying “not like this,” a security review, a deployment process that someone had to be taught. That friction was annoying and it was also load-bearing. It was where the questions got asked.
AI removed the friction and did not replace the questions. The app deploys itself, so nothing stops to ask whether it should.
We have watched companies take a demo to production because it looked finished. It looked finished because the parts you can see — the UI, the flows, the copy — are exactly the parts AI is best at. The parts that were missing are the parts you cannot see from the outside: authorization, migrations, observability, a deploy you can reverse. The app that goes down at 3am and the app that ships perfectly are visually identical right up until 3am.
Trusting the output was never the mistake. Trusting it without ever having defined what correct looked like was.
What we do instead
We are not the “hire humans, AI is a fad” people. We use these tools constantly. What we changed is what happens before the prompt — and the honest result is that we ship faster this way, not slower, because we are not rebuilding the same thing three times. This is the sequence behind every project we build for clients.
Requirements first, and written down. Before any code, we agree what the software must do, for whom, and what is explicitly out of scope. Not a wishlist — a document that says what happens when the payment fails, what an admin can see that a member cannot, what the system does when the third-party API is down. Most Day 30 disasters trace back to a question in this document that was never asked. AI cannot ask it for you, because AI has no stake in the answer.
Tech stack research, with the reasons attached. We pick the stack deliberately and we write down why: what it has to handle in two years, what the team can actually maintain, what it costs at scale, what happens if we need to leave it. Ten pages of reasoning that takes two days and saves a migration. An AI will use whatever is most common in its training data — a reasonable default, and not the same thing as a decision.
Every user flow documented before it is built. Each flow, start to finish: entry point, each state, each failure, what the user sees, what the system records, who is permitted to be here. This is the single highest-leverage document in the process. It is where authorization gets designed instead of assumed, and it is why “any customer can read any other customer’s invoices” cannot survive to production — the flow document says who is allowed, so the check has to exist.
Phases with real edges. The work is split into phases that each deliver something whole and verifiable, with defined boundaries and defined interfaces. This is what keeps a system coherent as it grows past the size any one context window — human or machine — can hold. Nobody has to remember the whole thing, because the shape is written down.
Then we execute — and this is where AI runs flat out. With requirements settled, the stack chosen, flows documented and phases drawn, generation is fast and safe, because every prompt is made inside a frame that already has the answers. The AI is no longer guessing at architecture. It is implementing a decision, which is what it is extraordinarily good at.
The tool did not change. The context we gave it did.
Already at Day 30? Run this triage today.
If any of this landed close to home, here is what to check first. It takes an afternoon and it is ordered by what will hurt you soonest.
- Search your client bundle for keys. Open the deployed app’s JavaScript in your browser’s network tab and search it for
key,secret, andtoken. Anything sensitive you find is already public — rotate it today, not this sprint. - Change an ID in a URL. Log in as one user, find a record URL, change the ID to a record belonging to someone else. If it loads, you have an authorization hole, and it is almost certainly not the only one.
- Try to recreate your database from scratch. If you cannot stand up an empty copy of your schema from files in the repository, you have no migration story and no safe way to change your data model.
- Ask someone new to deploy it. If deployment lives in one person’s head or one person’s terminal, that is a single point of failure wearing a lanyard.
- Grep for your core business logic. Pick the most important rule in your product — pricing, permissions, whatever — and search for it. Count the copies. That number is how many places a change has to land.
- Open the oldest file and the newest one. If they look like different codebases, you have context drift, and every new feature is now negotiating with two conventions.
None of these require a consultant. If they all come back clean, you are in far better shape than most, and you should carry on. If several came back badly, that is not a rewrite signal — it is a stabilization one, and the difference matters enormously to your budget.
The honest summary
Vibe coding is not the problem. It is a genuine step change in how fast software can be built, and the people dismissing it will be wrong in the same way people were wrong about compilers.
The problem is treating a technique that is excellent at building as though it were also a technique for deciding. It is not. It has no opinion about what your product should do, no memory of what it chose last month, and no stake in what happens at 3am.
Day 1 is real. Day 30 is also real. The distance between them is not measured in lines of code — it is measured in decisions that were never written down.
Write them down. Then let the machine go as fast as it likes.
We stabilize AI-generated codebases for a living — no rewrites, and you keep the code. Patchlane offers a free 48-hour audit that tells you exactly where you stand, whether or not you hire us afterwards.