How to Ship Your Vibe-Coded App: From Prototype to Production
You built an app with AI. It works on localhost. Now what? A step-by-step guide to closing the gap between vibe-coded prototype and production-ready application.
You described an app to an AI. Twenty minutes later, it works. The UI is polished. The features do what they are supposed to do. You can click through every flow and everything responds correctly.
Then you try to ship it, and reality intervenes.
The database has no access controls. The error handling is a patchwork of try-catch blocks and silent failures. The environment variables are scattered between .env.local and hardcoded strings. There are no tests. The mobile layout breaks in ways you did not notice on your laptop. The payment flow has no idempotency protection.
This is the gap. Every vibe-coded app has it. The AI tools that build these apps are extraordinary at generating functional code, and systematically blind to the unglamorous work that makes functional code production-safe.
This guide covers exactly what you need to do to close that gap.
What "Ship Ready" Actually Means
"It works" and "it is ready to ship" are separated by a specific, knowable set of requirements. Ship readiness is not a feeling. It is a checklist.
A production-ready web application must have:
-
Authentication and authorization that actually protects data. Not just a login screen, but proper middleware that blocks unauthenticated access to every protected route, and row-level security that prevents users from accessing each other's data.
-
Error handling that does not expose internals or crash the app. Error boundaries in your UI. Try-catch with meaningful fallbacks in your API routes. Structured error responses that tell the client what went wrong without leaking stack traces.
-
Environment configuration that works in production. No hardcoded secrets. No localhost URLs baked into API calls. A clear separation between public and private environment variables.
-
Deployment configuration that builds and runs. A production build that completes without errors. Correct platform configuration (Vercel, Netlify, Fly, etc). Health checks. Proper CORS and security headers.
-
Basic test coverage on critical paths. Your auth flow, your payment flow, your core CRUD operations. Not 100% coverage. Just enough that you know the important things work.
-
A UI that works on real devices. Responsive layouts that do not break on small screens. Loading states that show progress. Empty states that guide users. Accessibility basics: keyboard navigation, color contrast, screen reader labels.
These six categories map directly to how FinishKit evaluates your app: blockers, security, deploy, stability, tests, and UI. Each one represents a dimension where AI-generated code consistently falls short.
If you want the full checklist, we published a detailed AI Code Finishing Checklist that covers every item across these categories.
Why AI Tools Leave This Gap
This is not a criticism of AI coding tools. Cursor, Lovable, and Bolt are genuinely remarkable at what they do. But understanding why they leave the finishing gap helps you close it efficiently.
They Optimize for the Happy Path
When you prompt an AI to build a feature, it builds the feature. It generates the form that submits data. It does not generate the validation that rejects malformed data, the rate limiting that prevents abuse, the error handling that recovers when the database is unreachable, or the loading state that tells the user something is happening.
The happy path, the user does exactly what you expect, works beautifully. Every other path is a potential failure.
They Do Not Have Production Context
AI code generators do not know that your Supabase project has RLS disabled by default. They do not know that your Vercel deployment requires specific environment variables. They do not know that your Stripe webhook needs signature verification. They generate code in isolation from your production environment.
This is why you end up with apps that work perfectly in development and break immediately in production. The AI did not make a mistake. It just did not have the context to get production configuration right.
They Do Not Review Their Own Work
No AI coding tool sits down after generating your app and asks: "Is this actually safe to put in front of real users?" The generation step and the review step are completely separate. And most developers skip the review step because the generated app looks and feels finished.
This is the vibe coding trap. The output is so polished that it obscures the gaps underneath.
The Finishing Pass: Step by Step
Here is a concrete process for taking a vibe-coded app from "works on localhost" to "ready for real users."
Step 1: Run a Ship-Readiness Scan
Before you fix anything, you need to know what is broken. Manually auditing an AI-generated codebase is tedious and you will miss things, because you do not know what you do not know.
Run a FinishKit scan on your repository. In a few minutes, you get a Finish Plan: a prioritized list of every finding across all six categories, with severity ratings. This gives you a map of the work ahead instead of a vague sense that "something probably needs fixing."
Start with the critical and high-severity findings. These are the issues that will cause real problems for real users. Medium and low-severity findings matter, but they will not prevent you from launching safely.
Step 2: Fix Security First
Security issues are the highest-stakes findings in your Finish Plan. An app with a broken layout is embarrassing. An app with exposed user data is a lawsuit.
Common security gaps in AI-generated code:
- Missing authentication middleware. AI tools often generate authenticated pages but forget to protect the API routes those pages call. Check that every protected endpoint validates the user's session.
- No Row Level Security. If you use Supabase, your RLS policies determine whether users can access each other's data. AI tools frequently leave RLS disabled or misconfigured. Read our Supabase RLS guide for the full picture.
- Exposed secrets. Look for API keys, database URLs, or tokens that ended up in client-side code or committed to the repository. Any
NEXT_PUBLIC_variable is visible to everyone. - Missing input validation. Every form, every API route, every URL parameter needs validation. AI-generated code often accepts whatever the client sends without checking.
For a comprehensive list, see our guide on AI code security vulnerabilities.
Step 3: Verify Deployment Configuration
Your app needs to build and run in production, not just in npm run dev. Common deployment issues:
- Missing environment variables. List every env var your app references and verify it is set in your production environment. One missing variable can take down your entire app.
- Build errors. Run
npm run buildlocally before deploying. TypeScript errors, missing imports, and unused variable warnings that your dev server ignores will fail a production build. - Platform configuration. Verify your
vercel.json,fly.toml, or equivalent platform config. Check that your Node.js version, build commands, and output directories are correct. - Security headers. Add HSTS, X-Frame-Options, Content-Type-Options, and Referrer-Policy headers. These are easy to add and significantly improve your security posture.
Step 4: Add Error Handling
Go through your API routes and UI components and add error handling where it is missing:
- API routes: Every route handler should catch errors and return structured error responses. Never return raw error objects or stack traces to the client.
- React error boundaries: Add error boundaries at the layout level so a single component crash does not take down your entire app.
- Loading and empty states: Every data-fetching component needs a loading state (while data is arriving) and an empty state (when there is no data to show).
- Form error handling: Show validation errors inline. Handle submission failures gracefully. Do not let the user submit a form twice.
Step 5: Add Critical Tests
You do not need 100% test coverage. You need tests on the paths where failure has the highest cost:
- Authentication flow. Sign up, sign in, sign out, password reset. These must work.
- Payment flow. If you charge money, test the checkout flow end to end. Test webhook handling. Test edge cases like expired cards and duplicate submissions.
- Core CRUD. Whatever your app's primary function is, creating, reading, updating, and deleting that data needs tests.
For guidance on testing AI-generated code specifically, see Testing AI-Generated Code.
Step 6: Fix the UI
Last because it is lowest risk, but still important:
- Responsive layout. Open your app on a 375px-wide viewport (iPhone SE). Fix anything that overflows, overlaps, or becomes unusable.
- Accessibility basics. Add alt text to images. Ensure interactive elements are keyboard-accessible. Check color contrast ratios. Add ARIA labels where visual context is missing.
- Loading states. Replace any blank screens during data fetches with skeleton loaders or spinners.
Step 7: Run Another Scan
After fixing the critical issues, run another scan. Your Finish Plan should now show fewer findings and lower severity ratings. If critical or high-severity issues remain, address them before launching.
This iterative approach, scan, fix, scan, is more efficient than trying to catch everything in one pass.
The Cost of Skipping the Finishing Pass
Shipping an unfinished app is not free. The costs are real and they compound:
- Security incidents erode user trust permanently. One data leak, and your early adopters are gone.
- Production crashes make your product look unreliable during the critical early growth phase.
- Technical debt from AI-generated code is harder to fix later because you did not write it and may not fully understand it.
- Lost users who hit bugs in their first session rarely come back for a second one.
The finishing pass typically takes a few hours to a day, depending on your app's complexity. That is a small investment compared to the cost of launching with critical gaps.
Tools for the Finishing Pass
The AI tools that built your app are good at generating new code but not at auditing existing code. You need different tools for the finishing pass:
- FinishKit for holistic ship-readiness scanning across all six categories
- TypeScript strict mode for catching type errors before they reach production
- ESLint for code quality and consistency
- Your browser's dev tools for responsive testing and accessibility auditing
- A staging environment for testing production configuration before going live
FinishKit is the only tool on this list that was built specifically for the finishing pass. It understands the patterns in AI-generated code and knows what to look for.
FAQ
How long does the finishing pass take?
For a typical vibe-coded app (10-50 pages, authentication, database, one or two integrations), the finishing pass takes 2-8 hours depending on the severity of the findings. A FinishKit scan takes 2-5 minutes and gives you the map. The fixing is where the time goes.
Can I use AI to fix the issues AI created?
Yes, and you should. Once you know what needs fixing (via your Finish Plan), you can use Cursor or Copilot to implement the fixes. The key difference is that now you are directing the AI with specific, known requirements rather than hoping it gets things right on its own. FinishKit also generates patches for many findings, which you can apply directly.
Do I need to do a finishing pass every time I push code?
No. Run a full scan before launches, after major development sprints, and whenever you integrate significant new AI-generated code. For incremental changes, standard practices (TypeScript, ESLint, basic tests) are sufficient. Think of the finishing pass as a pre-launch gate, not a continuous process.
What if I do not fix everything in my Finish Plan?
Focus on critical and high-severity findings. These represent real risks to your users and your app's stability. Medium and low-severity findings are improvements that can wait. A Finish Plan is a prioritized guide, not an all-or-nothing requirement.
Your app is closer to launch than you think. Run a scan to see exactly what stands between you and production. It takes minutes, not hours.