I use AI on client work every week and I built an AI website generator that runs on Claude, GPT and Gemini. I'm not writing this as a sceptic. I'm writing it because I've spent more hours than I'd like recovering from the specific ways these tools fail, and almost nobody selling them will tell you what those are.
The benefits are real — I've written about the ones that survived contact with real projects. This is the other column of the ledger.
None of these limitations are reasons to avoid AI. They're the things you have to design around, and the cost of not knowing them is paid in production.
1. Confident wrongness is the expensive one
The defining problem is not that models are wrong. It's that being wrong looks exactly like being right.
A model is optimised to produce plausible output. Plausible is not the same as correct, and the two are indistinguishable at a glance. So the failure mode isn't code that won't run — that's cheap, you find it immediately. It's code that runs, looks entirely reasonable, and does something subtly different from what you asked.
The version that costs real money: a function that handles the normal case perfectly and gets an edge case wrong. It passes your quick check because you tested the normal case. It ships. Six weeks later someone submits a form with an apostrophe in their name, or a booking spanning a month boundary, and you're debugging something you never wrote.
Compare that to a human colleague. When a person is unsure, you can usually tell — hedged language, a comment, a question. A model produces uncertain output in exactly the same confident register as certain output. That signal, which is most of how code review works between people, simply isn't there.
Invented functions that ought to exist
The sharpest version: models invent methods that don't exist but plausibly should. A utility function with exactly the right name for the job, on a library that never shipped one. It reads perfectly. It fails immediately, which makes it a cheap bug — but it tells you something important about what the tool is doing, which is producing what the answer would look like rather than recalling what the answer is.
2. It's confidently out of date
Models learn from a snapshot. The web does not hold still.
So you get patterns that were correct two or three years ago, delivered with no indication anything has changed: deprecated APIs, configuration that moved, approaches the ecosystem has since abandoned for good reasons. On fast-moving frameworks this is constant.
What makes it costly is that outdated code often works. You don't get an error — you get a site built on a pattern that's been superseded, and you find out at upgrade time. Anything version-specific has to be checked against current documentation, every time. That check is now a permanent part of the workflow.
3. It doesn't know your project
A model knows what you showed it in this conversation. It has no memory of the decision you made three months ago and no feel for your conventions.
The practical result is duplication. You ask for a date formatter; you get a good one. You already had one, two folders away, with the timezone edge case handled. Now you have two, they disagree in one specific case, and nobody will notice until a booking shows the wrong day.
Multiply that across a project and you get a codebase of near-duplicates that all work individually and quietly contradict each other. This is one of the strongest arguments for the boring discipline of reading everything that gets added, and it gets worse the larger the codebase is — which is the opposite of how most tools are marketed.
4. Security is the gap that scares me most
Generated code reflects the average of what it learned from, and an enormous amount of public example code exists to demonstrate a concept, not to survive hostile input. Tutorials skip authorisation because it's noise in a tutorial. Sample code trusts its inputs because the sample controls them.
The recurring gaps I see:
- Missing authorisation checks. An endpoint that correctly verifies who you are and never checks whether you're allowed to touch this particular record. It works flawlessly in testing, because in testing you only ever request your own.
- Trusting client-supplied values. Prices, quantities, IDs and roles that arrive from the browser and get used as-is.
- Secrets in the wrong place. Keys that end up in client-side code or committed to the repository, because the example that pattern came from was a local demo.
- Error messages that overshare. Stack traces and query fragments returned to the user, which is a debugging convenience in development and a map of your system in production.
None of this is exotic. All of it ships easily, because none of it looks wrong. Anything touching authentication, payments or user data gets read line by line — that's a rule, not a preference. If you're commissioning work, this is the single most important thing to ask how someone handles.
5. The review burden nobody budgets for
Here's the trade that doesn't make it into the pitch: you spend less time producing and more time checking.
Reviewing code is genuinely harder than writing it. Writing, you build the mental model as you go. Reviewing, you have to reconstruct someone else's — and generated code has no author to ask, no reasoning to recover, no commit message explaining the choice.
The volume makes it worse. When output was limited by typing speed, review scaled naturally. Now you can produce more in an hour than you can carefully review in three, and that gap is precisely where things slip through. Skipping the review doesn't remove the cost; it moves it somewhere far more expensive.
6. Design converges on the average
Ask for a layout and you get the statistical centre of everything the model has seen. Competent, familiar, forgettable — which is the exact opposite of what a brand is paying for.
This is why AI-generated sites have a recognisable look. Not bad, just deeply average, and average is a commercial problem when the entire point is not resembling your competitors. For a creator with 600,000 subscribers, "competent and familiar" was the problem we were hired to solve — her store had to feel like her, and there is no prompt for that.
The same applies to copy. Models default to a register that reads as slightly corporate and slightly empty. It's serviceable as a draft for a client to react to; publishing it undermines the reason to build a custom site at all.
7. Skill atrophy, and the junior developer problem
This is the limitation with the longest tail, and it isn't really about the tool.
Judging generated code requires knowing what good looks like. That knowledge came from writing a lot of code by hand, including badly. If the next generation of developers skips that, they'll be able to produce far more than they can debug — which is fine right up until production breaks and there's no mental model to fall back on.
I notice it in myself on things I've stopped doing by hand. The muscle fades. My compromise is to keep writing some code from scratch even when generating would be faster, specifically to keep the judgment sharp — the judgment is the part that's actually worth money. If you're learning now, the path I'd take puts fundamentals first for exactly this reason.
8. Accessibility theatre
Ask a model to make a component accessible and you'll get ARIA attributes. Often correct ones. That's a real improvement over nothing.
But accessibility isn't an attribute problem, it's an experience problem. A model can add aria-label everywhere and still produce a flow that's incoherent with a screen reader, a focus order that jumps around, or a modal you can't escape. The markup passes automated checks; the experience fails a real user.
The gap between "passes the linter" and "works for someone using it" is not something generation closes. It needs testing with actual assistive technology, which is a different activity entirely.
9. If the AI is in the product, the limits get harder
Everything above is about building with AI. Shipping AI features inside a site adds a separate set of constraints that surprise people commissioning them.
Non-determinism. The same input can produce different output. Traditional testing assumes it doesn't. Testing a feature whose correct answer is a range rather than a value is a genuinely different discipline.
Latency. Model calls take seconds, not milliseconds. That has to be designed for honestly, and "it feels slow" is a conversion problem long before it's a technical one.
Cost per call. Every interaction costs money. A feature that's cheap in testing can be alarming at real traffic, and I've watched that arithmetic kill more concepts than any technical limitation.
Failure states. Providers have outages and rate limits. A feature without a sensible degraded mode is a feature that takes part of your site down with someone else's API.
It will confidently make things up to your customers. The mitigation is retrieval plus citations plus a real "I don't know" path — covered properly in RAG for business websites. Without that you've built a machine for inventing policies you don't have, at scale, in your own voice.
10. You're building on someone else's terms
A limitation that isn't technical and gets ignored until it matters.
If AI is part of how you build, a chunk of your capability now sits behind an API you don't control. Pricing changes. Rate limits change. Behaviour changes between releases in ways that are hard to predict — a prompt that worked reliably for months starts producing something subtly different, and nothing in your code changed.
For development assistance this is survivable; worst case you work the old way for a week. For a shipped AI feature it's a real operational risk, because your product's behaviour depends on a third party's decisions. Building so the model can be swapped is the mitigation, and it costs real effort up front that's tempting to skip.
There's a quieter version of this for clients: if your site was built in a way only one tool can maintain, you've acquired a dependency you didn't agree to. That's the same argument as owning your stack, pointed at a newer risk.
The failure modes, and what actually helps
| Limitation | How it shows up | Mitigation |
|---|---|---|
| Confident wrongness | Runs fine, subtly incorrect | Review as if from a stranger; test edge cases first |
| Stale knowledge | Deprecated patterns, no warning | Verify anything version-specific against current docs |
| No project context | Duplicate, disagreeing implementations | Read every addition; keep conventions explicit |
| Security gaps | Missing authorisation, trusted input | Line-by-line on auth, payments, user data |
| Review burden | Output outpaces careful checking | Budget review time explicitly; slow down output |
| Design convergence | Competent but generic | Use for structure, not for the parts that differentiate |
| Skill atrophy | Can't debug what you generated | Keep writing some code by hand, deliberately |
| Accessibility theatre | Passes linters, fails users | Test with real assistive technology |
| Non-determinism (AI features) | Untestable by normal means | Evaluate on real cases; design for a range |
The limitation I only saw by building the generator
Building an AI website generator taught me the ceiling better than building sites by hand ever could.
WebSeek does what it claims — one prompt, a working custom-coded site. Every genuinely hard problem in it turned out to be about knowing what the user meant, not generating code. Someone types "website for my restaurant" and the model must invent a hundred decisions nobody made: how many dishes, whether bookings matter more than the menu, whether people come for the food or the view.
It invents them plausibly. Sometimes well. Never knowingly — and that distinction is the whole limitation in one sentence. A model cannot know which decisions matter, because it has no stake in the outcome.
Running it across three providers made the second lesson obvious: swapping models changes the texture of the output and almost nothing about this problem. The ceiling isn't a model-quality issue that the next release fixes. It's structural.
If you're commissioning work
Three questions that separate supervision from delegation:
"What did you write by hand on this, and why?" A specific answer means someone is making decisions about where the tool is trusted. "We use the latest AI" means the tool is making them.
"How do you review generated code touching payments or user data?" You want to hear something process-shaped and slightly boring. Hesitation here is the answer.
"What have you rejected from a model recently?" Anyone working seriously with these tools has a recent example. No example means either no critical reading or no real use.
And treat compressed timelines carefully. AI shortens the build, not the project — discovery, content and review are untouched. When the school portal shipped in seven days, that was possible because the client answered questions the same day, every day. The scheduling was as much of the achievement as the engineering.
The honest summary
The limitations of AI in web development are not that it's bad at writing code. It's good at writing code. The limitations are that it doesn't know what you're trying to build, can't tell when it's wrong, has no memory of your project, and produces work that requires more review than it saves in typing if you're careless about it.
Design around those and it's the most useful tool to arrive in years. Ignore them and you'll ship something that looks finished, works in testing, and fails in the specific way nobody checked.
That's the whole trade. What genuinely changed, what you gain, and where it goes next are the rest of the picture.