Claude Code makes it incredibly easy to generate working APIs. They seem ok and they famously "work on my machine". Until real users show up and your application needs to perform under load.
When code is cheap, structure, boundaries, and decisions are everything. Software architecture matters now more than ever.
The problem isn’t that AI writes bad code.
It’s that production constraints are often an afterthought and AI will never assume them for you unless you explicitly prompt for it.
Below are the most common failure points I see in vibe coded APIs — and how a few precise prompt constraints completely change the outcome and reduce your headaches in the future.
Vibe coded endpoints accept unlimited requests by default.
Someone scripts 10,000 requests in minutes - intentionally or not - and your database falls over.
Be explicit about limits and enforcement.
“Limit requests to 100 per hour per user using Redis.
Return HTTP 429 with a Retry-After header when exceeded.”
This forces the model to design for abuse, not just correctness.
AI often writes get endpoints for “all records” because it’s the simplest solution that just works straight away.
A user with 50,000 records hits the endpoint once and crashes your server - or times out every request.
“Use cursor-based pagination.
Maximum 100 items per response per user.
Return nextCursor for infinite scrolling.”
Properly paginated endpoints are necessary for survival.
Generated APIs frequently assume “if you’re authenticated, you’re allowed.”
User A can read or mutate User B’s data by guessing an ID.
This is one of the fastest ways to ship a critical security bug.
“Enforce authorization on each request.
Return HTTP 403 on violation.”
Never let authorization be implied in your backend.
AI defaults to DELETE FROM table WHERE id = ?.
One accidental delete and data is gone forever. No audit trail, no logs.
“Use soft deletes through a status field.
On deletion, mark record's status as inactive.”
Production systems assume mistakes will happen.
Generated APIs often trust incoming input.
XSS payloads
Unexpected data shapes
Massive request bodies (10–16MB) that crash your app or DB
“Enforce strict validation schema for every input field, with explicit types, size limits, and sanitization rules”
Validation is a defensive boundary of your system.
Concurrent updates overwrite each other silently.
Two users edit the same resource. Last write wins. One user’s changes disappear without warning.
“Use optimistic locking.
Check updatedAt in the transaction.
Return HTTP 409 if the record has changed.”
Concurrency bugs don’t show up in demos on localhost.
Vibe coded APIs assume requests happen once.
Retries from clients create duplicate records in your DB.
“Require an idempotency key per request.
Return the cached result on retries.”
If retries exist, idempotency is mandatory.
Generated code sends emails, webhooks, or notifications before committing state.
Email sent while DB is updating records. DB write fails. System is now out of sync.
“Persist state first.
Trigger side effects only after a successful commit.”
Side effects must be downstream of truth.
External calls wait forever by default.
One slow dependency ties up your entire request pool.
“Set explicit timeouts.
Fail fast and return a controlled error.”
Latency is a failure mode.
Logs are an afterthought or missing entirely.
Something breaks and you can’t answer what happened or where, making your debugging a nightmare.
“Create structured logs for each user action, use correlation IDs for requests”
If you can’t see it, you can’t fix it.
In this day and age of founders vibe coding their entire applications using one or two prompts, knowing how to prompt properly and produce code that survives in the real world is a differentiation and a skill that makes a difference.
Solid list. The prompt constraint approach works but it highlights the real issue - you are doing the AI's job for it. Every one of these 10 points is something a senior dev would catch in review. The AI just skips them because it optimizes for "works on first run" not "survives in production."
The part that gets me is the review tax. Even if you nail all 10 constraints in your prompt, you still have to read every line of output to verify the AI actually followed them. And if you run the same prompt again tomorrow, you get different code. So your review starts from scratch every time.
We are building a frontend coding agent specifically to fix this. The idea is that if the generation is deterministic - same input, same output - then you only need to review a pattern once. After that, every future generation follows the approved pattern without re-review.
The backend side you described here is even harder because the failure modes are less visible. A missing rate limiter does not show up until someone actually hammers your endpoint.