July 29, 2026 - 4 min read
Engineering With AI: Getting Vibe-coded Apps to Scale and Stay Secure
- ai
- engineering
- security

Photo by Public domain vectors on Unsplash
"Vibe coding" (describing what you want and letting an LLM write the implementation) is genuinely good at getting something working. It is not, by default, good at getting something production-ready. Those are different bars, and the gap between them is exactly where scale problems and security holes live.
I use Claude, Codex, and ChatGPT daily. The output is often clean, idiomatic, and passes the happy path immediately. What it quietly skips, unless you ask, is almost everything that only matters once real users, real load, and real attackers show up.
Where AI-generated code tends to fall down
Concurrency. Ask for a "redeem points" endpoint and you'll usually get a read-then-write: check balance, then deduct. That's correct for one request at a time and wrong the moment two requests land together. On the rewards app I built, the actual requirement was an atomic transaction with a conditional stock decrement and an idempotency key on the redeem endpoint, none of which shows up unless you explicitly ask for "safe under concurrent requests."
N+1 queries and unbounded reads. Models default to the simplest correct query, not the one that scales. A loop that fetches related rows per item, or a list endpoint with no pagination, will work fine in a demo with ten rows and fall over at ten thousand.
Auth and secrets. I've seen generated code store JWTs in localStorage instead of secure storage, skip token expiry checks, or hardcode a "temporary" API key that survives into the commit history. None of this is malicious; it's just optimizing for "the demo works," which is a different objective than "this is safe to expose to the internet."
Input validation at the boundary. AI-written handlers often trust whatever the client sends. Validation, when it appears, tends to be client-side only, trivially bypassed by anyone calling the API directly.
What actually closes the gap
Say the non-functional requirement out loud. "Add a redeem endpoint" and "add a redeem endpoint that's safe under concurrent requests and can't be double-charged by a retried request" produce meaningfully different code from the same model. Scale and security requirements are rarely inferred; they have to be stated.
Review the diff like you'd review a junior engineer's PR. Not a skim: actually trace the data flow. Where does user input enter, what validates it, what does the query look like under load, what happens if this handler is called twice with the same payload. AI output benefits from exactly the same scrutiny human-written code needs; it doesn't get a pass for reading fluently.
Push validation and auth checks server-side, always. Treat every client input as hostile by default, regardless of what generated the client. Zod (or equivalent) at the API boundary, not just in the form.
Make correctness-under-concurrency a named check, not a hope. For anything touching a balance, inventory count, or once-only action: does this need a database transaction, a unique constraint, an idempotency key? If yes, ask for it explicitly, don't assume the first draft has it.
Run the tools that don't get tired. Static analysis, dependency audits, and a dedicated security-review pass over the diff catch the class of issue that's easy to miss when the code looks right. They're not a substitute for understanding the code, but they're a cheap second opinion.
Load-test before you trust it. A query that's fine at demo scale can be the thing that falls over first in production. If you can't say how an endpoint behaves at 100x the current load, you don't actually know yet, regardless of who or what wrote it.
The actual shift
None of this is really about AI. It's the same discipline that's always separated a prototype from a production system: validate at the boundary, design for concurrency, assume the network is hostile, measure before you trust. What's changed is the speed at which the first draft arrives. That's a real gain. It just means the review, the load thinking, and the security pass are now a larger share of the total effort than the initial implementation, not something you can skip because the code came out looking competent.
Vibe coding is a great way to get to a working prototype fast. It is not, on its own, an engineering process. That part is still on you.