Why your vibe coded site breaks the moment you deploy
I once shipped a site that passed every check I ran and still went out wrong. Not crashed, which you would at least notice. It looked completely fine and quietly served the wrong thing, which is worse, because nothing warns you.
That is the version of "works locally, breaks on deploy" that actually scares me, and it is the wall almost every vibe coder hits on their first real launch. The preview link works. You point a domain at it. And the public version behaves like a different app, because in a way it is one.
the folder that only existed on my laptop
The site had a small chatbot on it. The chatbot read its voice and its facts from a folder on disk at runtime, and in my preview that folder was right there, so it sounded exactly the way I had spent a week tuning it. What I had not clocked was that the folder was gitignored. It lived on my machine and inside the preview build, but it was never committed. And a deploy only ships what you committed.
So the version headed for production was going to boot up, look for that folder, find nothing, and answer real visitors in a flat default voice with none of the facts I had written. On my machine: exactly right. In production: a polite stranger. Same code, completely different behavior, and the only difference was one line in a gitignore file I had written weeks earlier and forgotten about.
I caught it before it shipped, and not because I am careful by nature. I caught it because the build had one boring habit baked into it. Before anything points at a real domain, write down every single thing the running app reads that is not its own source code. Env vars. The database. Uploaded assets. Any file it opens at runtime. Then go down that list and confirm each item actually exists on the target host, not just on my laptop. The folder failed that check on the first pass. Thirty seconds of reading a list beat five hours of a live chatbot embarrassing me in front of the first people who ever visited.
the preview is lying to you, politely
That is the shape of nearly every "works in preview, breaks on deploy" story, and it is the most common thing I watch vibe coders walk into. The preview environment is not lying on purpose, but it is lying. A managed preview quietly hands you a pile of things for free: environment variables injected from a dashboard, a database that is already connected, asset routing that just works, networking between services that is already wired, and every file sitting on the disk whether or not you ever committed it.
A real host hands you none of that by default. It gives you exactly what you committed and exactly what you configured, and nothing else. So the preview is not a smaller copy of production. It is a different environment wearing production's face. Everything that makes the preview feel effortless is the exact list of things that can vanish the second you deploy for real. I wrote a while back about the commit that shipped to nowhere; this is the same lesson from the other side of the push, the version you can still catch before anyone sees it.
make the gap a spec item, not a surprise
The move that turns this from a coin flip into a checklist is easy to say and easy to skip: verify in the real environment, not the friendly one. Write the list of everything your app depends on that is not its own source code, then verify each item against a production-equivalent target before you point a domain at anything. Preview-green is a claim. Production-equivalent-green is proof. Only one of them is the thing your visitors will actually load.
That is the same discipline behind building a site with AI and then hardening it for production. The build is the easy half. The half that decides whether real people load something that works is everything you do after it looks done.
A few specific items to put on the list, because they are the usual suspects:
Environment variables that live in a .env file on your machine. That file is almost always gitignored, so localhost reads it happily and production has no idea those values ever existed. Every "it works on my computer but the API calls fail live" is usually this.
A folder or file the app reads at runtime that never got committed, which is the one that nearly got me. If the running app opens it, the deploy has to include it, and gitignore does not care how important the file is.
Middleware or routing that silently eats a request in production that sailed through locally, so a manifest, an icon, an image, or a form endpoint just quietly returns nothing.
And the quiet one underneath all of them: "I tested it." Tested where? On your machine, in one browser, on desktop, signed in as yourself. Production is a stranger on a phone you have never seen, on a network you do not control, hitting the one path you never clicked.
why vibe coding makes this easier to walk into
Vibe coding makes this trap easier to fall into, and not because the tools are careless. They optimize for the loop you can see. The agent gets your preview working, the preview works, and the whole thing feels finished. Nobody in that loop is tracking which of the pieces making it work will actually travel to a real host. The preview turning green is the reward signal, and the preview is exactly the environment that hides the gap. So a vibe coded build looks done a full step before it is deployable, and the gap only surfaces at the worst possible moment, when a real person is finally looking.
The fix is not more caution in general, which never sticks anyway. It is one specific artifact: a short, written list of your app's runtime dependencies, checked against the actual place it is going to live. Boring on purpose. Boring is what survives a deploy.
If you are turning a vibe coded site into a real launch and want a second set of eyes on the preview-to-production jump before you point a domain at it, /work-with-us. Send me the build and where it is deploying, and I can walk the list of what the preview is quietly giving you for free and make sure the real host actually has it, or scope a spec-first pass so your next deploy is a checklist instead of a coin flip. Work with VibeKoded.
A site that works in preview is not telling you it is ready. It is telling you it works in the one place built to make it work. Ready is what you get after you have checked it somewhere that owes you nothing.