Six months ago a founder sent me a link to their product. Padel club management, B2B, pre-seed about to close. It worked. You could sign up, create a club, book a court, take a payment. They had built it in about three weeks without an engineer.
They were not asking me whether it worked. They knew it worked. They were asking the question that actually matters: "We have eleven clubs interested. What breaks?"
That is the right question, and almost nobody asks it early enough. This is the long answer.
The gap nobody warns you about
There is a specific moment that catches founders off guard. The prototype works. Demos go well. Money arrives. And then somewhere between the fiftieth and the five-thousandth user, the thing stops being a software problem and becomes an operations problem — and no one on the team knows how to tell which is which.
I have now audited six startup backends in a year. SaaS platforms in Europe. A marketplace in Dubai. A fintech in the US. Different products, different teams, wildly different budgets. The failures were nearly identical every time.
That repetition is the useful part. It means this is not bad luck or bad developers. It means the tooling that gets you to a working prototype systematically skips a specific set of decisions — and those decisions all come due at roughly the same moment.
What AI-built code actually gets right
Let me be precise, because the lazy version of this article is "AI code is bad" and that is not true and not useful.
AI-generated prototypes are usually correct at the feature level. The booking flow books. The auth flow authenticates. The payment integration charges the right card the right amount. If your prototype is doing the wrong thing functionally, that is a prompt problem and it is cheap to fix.
What they miss is not features. It is everything that only matters under conditions the prototype never experienced:
- more than one user doing the same thing at the same time
- a third-party API being slow instead of fast
- a request that fails halfway through
- data that has been accumulating for eight months
- someone malicious
None of those show up in a demo. All of them show up in month three.
The three failures, in the order they arrive
1. The service that does everything
Every prototype I have looked at has one. A single service — usually called something innocuous like api-server or main-backend — handling authentication, payments, notifications, user management, file uploads and analytics.
At the start this is genuinely the right call. One codebase, one deploy, one thing to watch. I would build it the same way. The problem is not that it exists; the problem is that nothing ever splits it, because splitting it is never the most urgent thing on any given Tuesday.
By the time you are at 50,000 users the consequences are concrete and unglamorous:
- a bug in notification code takes down checkout
- one slow query makes every endpoint slow
- you cannot scale the expensive part without scaling all of it
- two engineers cannot ship in the same week without colliding
What drives the cost of fixing it: how tangled the shared data is, whether the extracted piece touches payments, and whether you can move traffic gradually. Carving out the first service is a scoped, plannable piece of work. Carving it out after an outage, with customers watching, costs materially more — not in engineering hours but in the decisions you make badly under pressure.
I wrote about the honest version of this trade-off in Monolith to Microservices: The Honest Timeline, Budget, and Risk, including the cases where the answer is don't.
2. No back-pressure anywhere
This is the one that surprises people, and it is the most reliably fatal.
A prototype assumes work arrives at a manageable rate. Production does not work that way. Traffic is spiky, third parties stall, and retries pile onto whatever is already struggling. Without something absorbing that, one slow dependency takes the whole system down — not because it failed, but because everything queued behind it until memory ran out.
The fix is not a bigger server. It is a queue, a timeout, a circuit breaker and a sane retry policy — four things that take days to add up front and weeks to retrofit while on fire. I described the pattern in Handling High Concurrency in Node.js, and the caching layers that sit in front of it in the 4-layer caching strategy I used to handle 600K concurrent users.
3. Data model decisions that quietly harden
The third one is the most expensive and the least visible.
Prototypes get built table by table, as features arrive. That produces schemas where the important relationships are implicit — a status stored as free text, a tenant boundary enforced in application code rather than the database, money as a float. Every one of those is fine at a thousand rows.
At a million rows, with real customers and real money, each is a migration with downtime risk. The float-for-money one in particular tends to surface as a reconciliation problem months later, which is the worst possible way to find it.
This is the real reason "cheap" development is expensive. Not code quality in the abstract — I have seen plenty of tidy code with a schema that cannot survive growth. It is that the decisions which are cheapest to make early are the ones nobody makes when the goal is a demo. More on that in The Hidden Cost of "Cheap" Development.
What to do about it, in order
You do not need to fix everything. You need to fix things in the order they will hurt you. Roughly:
Before your first paying customer
- Money as integers, not floats. Non-negotiable, trivial now, awful later.
- Tenant isolation enforced in the database, not just in code.
- One environment that is not your laptop.
Before 1,000 users
- Timeouts and retry limits on every external call.
- Error tracking you actually look at.
- Backups you have restored from at least once — an untested backup is a rumour, not a backup.
Before 10,000 users
- A queue for anything slow (email, exports, webhooks, AI calls).
- Caching at the layer that is actually hot, not the one easiest to cache.
- Split out the first service — usually whichever part scales differently from the rest.
Before you raise the next round
- Someone who is not the founder able to deploy and roll back.
Notice how little of this is glamorous, and how none of it is "rewrite it properly." The single most expensive mistake I see is the opposite instinct — the full rebuild. It fails for reasons I laid out in The "Big Bang" Rewrite Is a Trap. The version that works is boring and incremental: strangle the old thing one route at a time, which is how we moved a legacy Java backend to Node.js without a day of downtime.
What this costs, honestly
I am not going to quote a rate here, because the honest answer depends on things I cannot know from a blog post. What I can tell you is what drives the number:
- How much traffic you actually have. Below a few thousand users most of this is a two-to-four week hardening pass, not a rebuild.
- Whether money moves through it. Payments and multi-tenancy raise the floor.
- Whether anyone stays after. Handing a hardened system to a team that cannot operate it buys you months, not years.
The thing that makes it more expensive is almost always waiting until something has already broken. Not because the engineering is harder, but because you lose the ability to sequence it — you end up fixing whatever is on fire instead of whatever matters most.
The uncomfortable conclusion
AI tools genuinely changed what one person can build. That part of the hype is real, and I use them daily. What they did not change is what production demands: concurrency, failure handling, data integrity, and the ability for someone other than the author to operate the thing at 3am.
The prototype was never supposed to be the product. It was supposed to be the proof that the product is worth building. Treat it as evidence, not as a foundation, and the next stage is a manageable engineering project instead of a crisis.
If you are somewhere in this gap right now — prototype works, users arriving, quietly unsure what breaks first — that is exactly the right time to ask. It is also, for what it is worth, the cheapest.
Read next
The rest of this series goes deeper on each stage of the gap:
- Vibe Coding Gets You the Prototype. Engineering Gets You the Product. — the shortest statement of the argument above.
- I Audited Multiple Startup Backends. They All Had the Same 3 Problems. — the same three failures, seen across six real codebases.
- The Hidden Cost of "Cheap" Development — why the decisions skipped early are the expensive ones.
- How We Built a SaaS App That Scaled to 10K Users — what the hardened version actually looks like.
- Launch Your Job Portal MVP in Just 4 Weeks — building it properly from the start, on a real timeline.
- The Real Cost of Quick Fixes — how shortcuts compound into something your board notices.
