Don't ship the prototype as the product

The prototype works. You can demo it. The happy path goes end to end. Stakeholders are impressed. The temptation now is to ship the prototype as the product because the prototype already exists and shipping faster feels like winning. The temptation usually wins because nobody wants to do more work on something that's already working.

The temptation is the trap. A prototype that works in demo conditions and a product that works for real users are different things, and treating them as the same thing is one of the most consistent reasons AI-built apps fail after launch. The prototype proves the concept. The product handles the conditions the concept didn't anticipate.

I want to walk through the five things that actually distinguish prototype from product, then the bridge work that converts one into the other. The goal is to give you a defensible answer to "is this shippable as production" rather than the optimistic answer the team wants to hear.

Distinction one: error handling

The prototype has happy-path error handling. Inputs that match the expected shape produce expected outputs. Inputs that don't match either get rejected with a generic error or, more often, cause unhandled exceptions that crash the relevant code path.

The product handles errors the prototype didn't think about. Malformed input. Missing fields. Wrong types. Empty strings where text was expected. Numbers outside expected ranges. Network failures mid-operation. Timeouts. Race conditions when multiple users do the same thing simultaneously. Each one of these requires deliberate handling in product code. The prototype usually has none of it.

The test: take your prototype, give it deliberately wrong inputs, and see what happens. If most of them produce useful error messages and graceful degradation, the prototype is closer to product than usual. If most produce crashes, stack traces, or undefined behavior, the prototype needs error-handling work before it ships.

Distinction two: edge case coverage

The prototype handles the cases the developer thought about. The product handles the cases real users actually do.

Real users do things the developer didn't anticipate. They paste unicode characters into fields that expected ASCII. They submit forms twice rapidly. They navigate backward through flows. They have ad blockers, privacy browsers, or screen readers. They use the app on browsers and devices the developer never tested.

The prototype works for the small set of cases the team explicitly tested. The product has to work for the much larger set of cases real users present. Closing that gap is real work that doesn't get done in prototype stage.

The test: have someone unfamiliar with the prototype try to use it as a real user would. Note every place they get confused, stuck, or surprised. Each of those is an edge case the product needs to handle but the prototype doesn't.

Distinction three: failure visibility

The prototype fails silently or fails loudly to whoever is in the room with the demo. The product fails in production where nobody is watching, and someone needs to find out before the user experience degrades further.

This means monitoring, alerting, error tracking. When the product breaks at 3 AM, someone (or some system) needs to know. When the product starts behaving differently than expected, the signal needs to surface before users complain. None of this exists in prototype stage.

The test: simulate a failure in your prototype. Disconnect the database. Make an API call return an error. Crash a service the app depends on. Now ask: how would I know this had happened in production? If the answer is "I'd find out when a user complained," that's prototype-level observability, not product-level.

Distinction four: data durability

The prototype stores data in development. Maybe a local database. Maybe a development account on a vendor's free tier. The data is testable but not durable. Loss is acceptable because the data is fake.

The product stores real user data. Loss is not acceptable. Backups, replication, recovery procedures, retention policies, data export, account deletion. All of this is product-level concern that prototypes usually skip.

The test: ask what happens if your database disappears right now. If the answer is "I'd restore from a backup," confirm the backup actually exists and the restore actually works (most people who think they have backups discover at restore time that they don't). If the answer is "I'd lose all the data," that's prototype-level durability.

Distinction five: scaling under load

The prototype works for the one user (you) testing it. The product needs to work for the realistic load of actual users. That load reveals problems the single-user case never shows: database queries that don't scale, API rate limits that get hit, caches that need to be warmed, race conditions that emerge under concurrency.

The test: simulate realistic load against your prototype. A load test tool generating concurrent requests at expected production volume. Watch for what breaks. Each break is a scaling problem the product version needs to address.

For most early-stage products, the "realistic load" is small enough that this distinction matters less. As load grows, the prototype patterns increasingly fail.

The temptation to ship anyway

The temptation to ship the prototype as the product is rational at the moment of decision. The prototype works. Shipping faster is better. The product-grade work feels like over-engineering. Why not just go.

The reason not to: each of the five distinctions above represents a class of failure that will happen in production. Users will hit error paths the prototype didn't handle. Users will encounter edge cases the prototype didn't cover. The system will fail in production with no observability to diagnose. Real user data will be at risk because durability wasn't designed for. Scale will reveal scaling problems.

Each failure costs trust with real users. Each failure costs operator time to firefight. Each failure costs business outcomes that depended on the system actually working. The cumulative cost of shipping prototype-as-product usually exceeds the cost of doing the bridge work before shipping.

The temptation wins anyway in most cases because the bridge work is invisible. The team doesn't see the failures that didn't happen because they ran the bridge work. They only see the time they're spending on what feels like duplicate work.

The Amendment D case study

I made this exact mistake on this site. The original intake form was a third-party iframe embed that worked in my testing. Prototype-grade implementation: rendered fine, submission went somewhere, the demo flow completed. Shipped as production.

Real users started arriving on real browsers. Brave Shields with default privacy settings blocked the iframe entirely. A meaningful slice of my actual audience saw a blank space where the form was supposed to be. Submissions vanished without me knowing.

The fix was Amendment D: rebuild the form as native React rendering on my own domain, posting through a clean API call to Formspree as the form-handling backend. The user-facing experience is identical. The shield blocking problem goes away because there's no third-party iframe to block.

The bridge work I should have done at MVP stage: test the form in privacy browsers, recognize that third-party embeds are vulnerable to shield blocking, design native-form architecture from the start. The work I actually did at MVP stage: ship the prototype embed because it worked in my browser. The result: a live pivot to fix what should have been right the first time.

The pivot was useful (the native form is better than the iframe would have been even after I worked around the blocking), but the timing was expensive. Doing the bridge work upfront would have saved the pivot. Worth knowing for the next build.

The bridge work

The work that converts prototype to product, in rough priority order:

Add error handling for the obvious failure modes. Malformed input, missing fields, network errors, timeouts. Not exhaustive; just the categories that account for most production failures.

Test against realistic conditions. Different browsers. Different devices. Privacy shields. Throttled connections. Real user data. Each test surfaces gaps the prototype's narrow testing missed.

Add observability. Structured logs, error tracking, basic health checks. Enough to know when production breaks and to diagnose why.

Address data durability. Backups, recovery procedures, retention policies. Whatever level is appropriate to the data the product handles.

Load test if scale is going to matter. Find the scaling problems before users do.

This is real work. It's also the work that separates "a demo that worked" from "a product that works." Skipping it is the trap. Doing it deliberately is what produces apps that hold up after launch.

The honest framing: if you're tempted to ship a prototype as the product, do the bridge work first. The cost is meaningful but bounded. The cost of skipping it is unbounded and recurring.


Got a prototype that works in demo conditions and you're not sure whether to ship as-is or do the bridge work first? Send the prototype state, the user load expected, and the consequences of failure. VibeKoded can scope the prototype, build the MVP, or hand off the production app. → Work with VibeKoded