The Limitations of Vibe Coding, From Someone Who Ships With It

By ·

Where vibe coding bites: confident wrong code, local solutions, complexity hidden behind pretty UI, security blind spots — and the habits that catch each.

I vibe code every day and I’ll defend it happily. Which is exactly why I get to write this page: the limitations are real, they follow patterns, and pretending otherwise is how the term got its bad reputation.

AI is good at making things work. It is much less good at knowing whether things should work that way. Everything below is a variation of that sentence, observed while shipping actual products.

1. It writes confident code, not correct code

The most dangerous property of AI-generated code is its tone. It doesn’t hesitate. It doesn’t make the small facial expression an experienced developer makes when a function starts knowing too much about the rest of the system. It just continues — like an intern with production access and no natural fear.

The fix isn’t distrust of everything; that’s paralysis. It’s calibrated distrust: the more a diff touches money, auth, permissions or deletion, the slower you read it. My rule of thumb: anything that can lose a user’s data gets read twice, once backwards.

2. It loves local solutions

Point at a problem and the AI solves that problem — fast, and with no regard for the long-term shape of the product unless you made that shape extremely explicit.

Building HeadToHead, it was tempting to just ask for “a leaderboard component.” Fine. But if point calculation, matches, users and history aren’t designed to hang together, you end up with logic smeared across components, hooks and small helpers with names like calculatePointsNewFinal2. A name I have naturally never used. Not publicly.

The countermeasure is the plan-before-code step: make the AI show you where the logic will live before any of it exists.

3. It hides complexity behind pretty UI

Tailwind plus modern component patterns means anything can look finished in an hour. That’s delightful and it’s a trap: a screen can look like a product long before it is one.

There’s a canyon between a prototype that displays quiz questions and Quiz Fight — 500,000+ AI-generated questions where quality, categories, performance and navigation have to hold up over time. Vibe coding gets you to the demo fast. But the demo is not the destination; the demo is where the problems put on nice clothes.

4. It doesn’t clean up after itself

Fast building leaves residue: components that should be split, queries that should be cached, types that quietly widened, decisions that were fine on Tuesday and are now load-bearing. The AI will never propose the cleanup on its own — it has no discomfort. You have to schedule it, which is why my workflow has a deliberate tightening rhythm.

5. Security and permissions are blind spots by default

Not because models can’t reason about security — because security is exactly the kind of requirement that lives outside the visible feature. The AI builds what you describe; attackers use what you didn’t. Firestore rules, role checks, rate limits, “what happens if this ID belongs to someone else” — I’ve learned to prompt for these explicitly, test them manually, and never accept a generated security rule I can’t explain out loud.

If you can’t explain a permission model to another human, you don’t have a permission model. You have vibes, and this is the one place the word stops being charming.

6. Game feel, taste and “is this good?” remain human work

AI generates a working Three.js scene shockingly well. What it can’t tell you is whether the dolphin feels heavy enough when it leaves the water. Anything whose acceptance test is a feeling — game feel, microcopy tone, whether a flow is pleasant — still needs a human who can tell the difference, repeatedly, at 23:41.

The honest summary

Every limitation above has the same shape: the AI optimises for the thing you pointed at; nobody is optimising for the whole unless you are. That’s why the developer doesn’t disappear from vibe coding — the developer becomes the part of the system that holds the whole.

None of this is a reason not to vibe code. It’s the reason to do it with a workflow instead of with hope. And if you’re honest about the limitations, you get to enjoy the genuinely absurd upside — here’s what it has shipped for me.