Production-ready code means the app’s critical claims have evidence: ownership checks hold across accounts, money is decided server-side, failures are visible, deployments are gated, and data can be restored. A demo that ran without an error proves none of those.
Used any other way, production ready is a mood. A founder looks at an app that works, remembers a testing session that went fine, and calls it ready. Ask what specifically makes that true and the answer usually describes a proof of concept: it ran the happy path, and nothing broke while someone clicked around.
These five checks are a baseline for a small web app, not an exhaustive standard for every workload or regulated industry:
- 01 Create a second account and try to read or change the first account’s rows by editing IDs inside the API calls
- 02 Try a paid action from an unpaid or cancelled account, then alter the response and try again; the server should deny both
- 03 Break something on purpose in a test environment and see whether the error reaches a person
- 04 Restore from a backup once, on purpose, and time it
- 05 Confirm the deploy runs your type checker and tests before shipping, and that you can put the previous version back
Each one is checkable today, without waiting for a real user to prove it the hard way. The launch readiness checklist turns that definition into launch-week actions. The production ownership guide covers the work after launch.
Production ready is a short list of claims about the code you already shipped, and every one of them is checkable before a real user proves it the hard way.
Why a production readiness checklist misses real failures
Search for a production ready code checklist and you get the reasonable list software engineering has long used: tests pass, monitoring is wired up, there’s a rollback plan, the on-call person has docs, someone reviewed the diff. That list catches real gaps when each answer is backed by evidence. It becomes weak when the review checks only whether an artifact exists.
Vibe-coded repositories make this mistake easy to miss. A generator can add an artifact without wiring it into the running application. A rate limiter can sit in the repo and protect nothing. A test folder can exist without exercising checkout. An error boundary can be written and never mounted. A review that asks only “is it there” cannot distinguish presence from working behavior.
| Looks ready | Is ready |
|---|---|
| The demo runs start to finish without an error | A second account, created after yours, can’t read or edit the first account’s data through the API |
| The repo has a tests folder | The suite actually executes the signup, the checkout, and the webhook, the three paths that touch identity and money |
| The deploy finishes green | The deploy step runs your type checker and your tests before it ships, not just the bundler |
| Nothing has broken in front of you yet | A failure anywhere reaches a person within minutes, without a customer reporting it first |
| Backups are turned on | You have actually restored from one, and know how long it takes |
Every row on the right is checkable without relying on the app’s source as proof. An artifact-only review asks whether something exists. A production-readiness review asks whether the claimed behavior holds.
Where AI-built apps actually fail: 26 audited apps
In AxonBuild’s fixed June and July 2026 research cohort, none of 26 AI-built apps reached the study’s green band. Research scores ranged from 29 to 81, with a mean of 52.1. These are historical research scores with the cohort and method documented; nothing AxonBuild does today produces a score.
One of the apps I audited, a motorsport dashboard, scored 63 with no critical findings. The config had ignoreBuildErrors and ignoreDuringBuilds switched on over an otherwise strict setup, so a deploy could report success without passing the type or lint checks. There was no error boundary either, so a malformed record could white-screen the whole app. Nothing about either gap shows up in a clean demo.
Across the full set, the gaps cluster in the same places, ranked by average score across the 21 third-party apps (0 to 100, pillars with no attack surface excluded rather than zeroed):
| Pillar | Average score | What it measures |
|---|---|---|
| Reliability & correctness | 31.4 | Does the app behave the same way twice, and does anything catch it when it doesn’t |
| Dependencies & supply chain | 34.5 | Are the framework and packages current, and is a known exploit reachable |
| Deployment & operations | 37.0 | Does anything gate a push before it reaches production |
| Performance & scale | 53.3 | Does it hold up under real traffic |
| Secrets & credentials | 84.4 | Are keys kept out of the client and out of git history |
That last row is the surprise. Secrets were the strongest pillar in this fixed sample, while reliability, dependencies, and deployment were the weakest. Those lower scores came from less visible engineering: whether behavior stays correct, whether a reachable vulnerable dependency gets patched, and whether anything checks a commit before production. The full 12-pillar ranking covers the rest, alongside the seven questions a launch actually turns on.
Can AI write production-ready code?
AI can produce usable code, but it cannot prove that code belongs in production. It hands the result over unchecked, which is a different problem from writing code that is visibly broken. Veracode’s Spring 2026 update reports a 55% security pass rate across its continuing test program of more than 150 models, while syntax correctness exceeded 95%. The test uses 80 narrowly defined tasks across four languages and four vulnerability classes, so it measures those scenarios rather than the full production-readiness question.
That gap between syntax and security is the whole story. A working build tells you the first number. Nothing in your repo tells you the second.
What AI code generators get right
More than the stereotype suggests. In the fixed 21-app third-party sample, secrets and credentials was the strongest pillar at 84.4 out of 100: most generators do keep API keys server-side and out of the bundle. Structure is usually reasonable, the framework conventions are followed, and the feature you asked for works on the path you demoed. Generators are good at producing the thing. They are not built to prove it.
What they leave unverified
The same short list, over and over, across the 21 third-party apps in that cohort. It is nearly all backend work, which is why production ready backend code is the harder half of the claim: a demo never exercises any of it.
- Ownership checks on API routes. 7 of 21 let a logged-in user read or write another customer’s rows, and 9 of 21 had row-level security gaps. The generator checks that you are logged in, not that you own the row.
- Error tracking. 17 of 21 recorded errors nowhere. A user hits a failure and it disappears.
- Deploy gates. At least 17 of 21 had nothing checking a push before it reached production, and some switched off their own type and lint checks at build time.
- Working tests. 18 of 21 had no automated test that actually ran, including one whose checkout suite never executed the checkout code.
- Built but not wired. Rate-limit buckets never attached to a route, error boundaries never mounted, a safety rulebook no running code reads. One app’s webhook signature check failed open whenever its secret was unset.
The first item has a name outside this cohort. OWASP tracks it as API1:2023, Broken Object Level Authorization, exploited by manipulating the object ID sent inside a request. It is the number one API risk in that list, and it is exactly what check one tests.
Does it differ by tool?
Not for the five checks. A vibe coded app is production ready on the same evidence whichever builder wrote it. What changes is where the boundary sits and who owns it.
Lovable Cloud includes a database, authentication, storage, secrets, jobs, and edge functions, so its ownership boundary spans every place that reads data or performs an action. Row-level security is one part of that boundary, not the whole of it. Supabase’s own docs say RLS is enabled by default on tables created with the Table Editor, and that you have to enable it yourself on tables created in raw SQL. A generator writing a migration takes the second path, which is why testing RLS with a second account is the check rather than reading the policy. Authentication, storage rules, and authorization inside edge functions and jobs need their own checks. Base44 keeps the database behind its own builder. Bolt, Replit and v0 hand you an app you host. Cursor and Claude Code edit a repo you already own, so the deploy gate, the rollback and the alerting stay entirely yours.
Newer and older names land on the same two poles. Figma Make publishes to a hosted public URL and also lets you export the code, so the running app and the exported copy are two things to keep straight before you test either one. Rork and Hostinger Horizons are more recent entries on the same spectrum. FlutterFlow can push the project to a GitHub repository on the paid Growth plan, and its data sits in a Firebase or Supabase project you connect yourself, which puts its boundary back on a database rule. Bubble keeps the whole app inside Bubble, and its privacy rules grant access rather than prohibit it, so what a second account can read is whatever the rules you wrote allow.
Different surfaces, same unanswered question: has anyone tried it from a second account? Lovable’s own passing checks do not answer it either.
Production ready vs production grade vs MVP
Three terms get used for the same app at different moments, and Google folds them into one search. Production level code is a fourth phrasing, usually meaning production grade. They are not the same claim.
| Term | What it describes | What proves it |
|---|---|---|
| MVP or proof of concept | The smallest build that shows the idea works | One person completes the happy path once |
| Production grade | The code itself: readability, structure, maintainability, testability, review | Another engineer can read it and change it safely |
| Production ready | Verified behavior under real users, real payments, real failures | Evidence from outside the source: a second account denied, a payment denied server-side, an alert that arrived, a restore that finished, a deploy that blocked a broken build |
Code can be production grade and still not production ready. A tidy, well-named, well-tested codebase whose ownership rules nobody has probed from a second account is exactly that.
Readability, maintainability, testability and code review are real. This article ranks them below verified behavior for one reason: a founder cannot check them without an engineer, and none of them predicts whether the app leaks a row. Code craft decides how expensive next quarter is, which matters more as an AI-built app gets harder to change. Verified behavior decides whether you should launch this week.
Five checks you can run
Most advice on how to write production ready code describes how the source should look. What production ready code looks like from the outside is simpler: five claims with evidence behind them. None of the checks below require the source as proof. Source review can explain a failure, but observed behavior and deploy or restore evidence decide whether the claim holds. That also makes them usable on code you did not write:
- Create a second account. Use it to request, then modify, the first account’s rows by editing IDs inside the API calls themselves, not page URLs. A row returned or a write that succeeds is a leak.
- If the app has paid access, use a test environment to try a paid action from an unpaid or cancelled account, then alter the browser response or local state and try again. The server should deny both attempts. A forged or unsigned payment webhook must not unlock access either.
- Break something on purpose in a test environment and watch where the error lands. If it lands nowhere, a real failure will be invisible too. The engineering words for this are monitoring, alerting and observability, and at your size it means an error reaches your phone or inbox, not a dashboard nobody opens.
- Restore from a backup once, on purpose, and time it. Backups being on and backups actually working are different claims. This is the whole of disaster recovery for a small app, and a restore drill is how you close it.
- Confirm the deploy step runs your type checker and your test suite, not just the bundler, before anything reaches production. Then confirm you can put the previous version back, and that you have done it once. Rolling back a database migration is the half of rollback that fails, because code goes back and data does not.
That list is the practical form of the seven questions a launch turns on. It is also how to make an app production ready in practice: run the five, fix whatever fails, run them again. Most checks can start in one focused session, but a realistic restore or deployment test may take longer. Nothing about a working demo answers any of them for you.
When lighter operating practices are reasonable
A small app may use lighter versions of enterprise practices, but headcount and user count do not make a control irrelevant. Decide from the consequence of failure, written obligations, workload shape, recovery options, and who must respond.
| Practice | Consider deferring while | Bring forward when |
|---|---|---|
| SLOs, SLAs and error budgets | No written uptime objective exists, outage consequences are low, and a simpler user-facing reliability target is documented | Customers depend on availability, recovery time matters, or a contract names a service level |
| On-call rotation and runbooks | One accountable operator receives working alerts and has a tested recovery path during the hours the service promises | Critical failures can happen outside that person’s availability, or another person shares response responsibility |
| Load testing for traffic spikes | Measured peaks have clear headroom and no launch, press, campaign, or expensive shared endpoint is expected to change the workload | A planned event or growth step can concentrate requests, or current telemetry approaches a resource ceiling |
| Chaos testing | Representative dependency-failure and restore checks have not yet been completed | A dependency failure has high user, safety, financial, or recovery consequence and ordinary failure tests no longer cover it |
| A formal production readiness review | One accountable owner can show evidence for the relevant checks without extra ceremony | Sensitive data, regulated duties, high-consequence workflows, or work crossing people makes an independent gate valuable |
| A separate staging environment | Destructive tests can run without touching customer data or the only recoverable copy | Real customer rows or irreversible external effects exist in the production path |
The last row is the one people skip wrongly. Testing against the production database is not a scale problem, it is a data-loss problem, and one database with no staging breaks the same way at 10 users as at 10,000.
In the fixed 21-app sample, performance and scale averaged 53.3 out of 100 while reliability and correctness averaged 31.4. That cross-sectional score difference shows that these audited apps scored lower on reliability and correctness; it does not establish which failure happened first or predict the sequence for another app. Treat correctness and capacity as independent checks, then set performance work from the app’s user consequences, expected workload, and measured headroom.
Common questions about production-ready code
What is production ready code?
Production ready code means code whose critical failure modes have already been checked, not code that merely runs. In practice: access to every row is checked by ownership, not just login; payments are confirmed by the server before anything unlocks; errors reach a person; and data has actually been restored at least once, not just backed up. If any of those is unverified, all you know for certain is that the demo worked.
Is AI-generated code production ready?
Not as delivered. AI can produce syntactically correct, usable code, but it arrives unverified, and the gap is measurable: Veracode’s Spring 2026 program reports syntax correctness above 95% against a 55% security pass rate across more than 150 models. Across the 21 third-party apps in our fixed research cohort, the recurring holes were ownership checks on API routes, error tracking, deploy gates and working tests. A working feature can be worth keeping. The evidence still has to show that it is safe to run in production.
What makes code production grade?
Production grade describes the code itself: readable, consistently structured, testable, and reviewed by someone other than the author. It is a judgment about the source. Production ready is a judgment about observed behavior under real users, payments and failures. An app can be production grade and still leak one customer’s rows to another, because nobody probed it from a second account.
Does a passing security scan mean my code is production ready?
No. A scan establishes only what that scan tested. A static or configuration scan may confirm that row-level security is enabled or that a known key is absent from a bundle, but it cannot establish every ownership rule, payment transition, restore path, or operational response. The comparison table earlier in this post shows the gap between an artifact being present and its behavior holding for a second account.
How do I know if code someone else built is production ready?
Run the same five checks. None of them needs source access, which is the point: you create a second account and try to read the first account’s rows, you try a paid action from an unpaid account, you break something and see whether anyone is told, you ask for a restore to be performed in front of you, and you ask to see the deploy log showing the type checker and tests running. A contractor who cannot show those five results has not proved the claim, whatever the repo looks like.
What does production ready mean for an app with 100 users?
At 100 users, begin with evidence for ownership checks, server-side payment decisions, error delivery, a performed restore, and a deploy gate. Add a service objective, load test, response plan, runbook, or independent review whenever the workload, failure consequence, written obligation, architecture, or shared responsibility makes that evidence necessary. User count alone does not settle the decision.
Is Lovable code production ready?
Not automatically, and the same answer applies to Base44, Bolt, Replit, v0, Cursor and Claude Code. The generator decides where the ownership boundary sits, not whether it holds. On a Lovable app the boundary is usually a row-level security policy, so the check is a second account trying to read the first account’s rows through the API. The full pass for a Lovable app walks the same tests tool by tool.
How long does checking actually take?
The access, payment, and failure-visibility checks can often run in one focused session. A realistic restore or deployment exercise can take longer, especially when the app has no separate test environment. Tracing whether a flagged dependency is reachable from running code can also require a second set of eyes, which is one of the decisions covered in when an AI app security audit is worth paying for.
Not sure what your app needs yet?
See how we follow one real problem from the behavior through the code and decide what should happen next.