The vibe coder pre-launch checklist: what actually breaks in production

You shipped it in a weekend with Cursor. Now it has users. Here's the unglamorous list of things that break when AI-generated code meets real traffic, real money, and real people.

The vibe coder pre-launch checklist: what actually breaks in production

You spent a weekend with Cursor and Claude Code. You have a working app. People are signing up. Congratulations — you are now in the most dangerous phase of the project.

This is the part nobody warns vibe coders about. The LLM is excellent at getting you to 80%. Production is the other 80%. Below is the checklist I run before letting anything I’ve built with AI tools touch real users. It comes from shipping things that broke, not from a Twitter thread.

The stuff that breaks first

1. Your API keys are in the client bundle

This happens constantly. The AI helpfully wires up an OpenAI call from a React component because that’s what the prompt asked for. It works. It ships. Someone opens DevTools and finds your key.

Go open your built JS bundle right now and grep for sk-, xoxb-, AIza, and your Supabase service role key. If anything hits, you have until someone notices.

# from your build output directory
grep -r "sk-\|service_role\|AIza" ./dist ./build ./.next/static 2>/dev/null

Fix: move every third-party call behind a server route. Yes, even the “just a demo” one.

2. No rate limits on anything that costs money

If your app calls an LLM, generates images, or sends email — and there is no rate limit per user, per IP, and per global budget — you are one bored teenager away from a five-figure bill.

Minimum viable protection:

Upstash, Vercel’s rate limiter, or a dumb Redis counter all work. The point is having one.

3. The database has no indexes

The AI wrote your schema. It probably did not add indexes beyond primary keys. Everything is fast at 100 rows. At 100,000 rows your dashboard takes 12 seconds to load and your Postgres CPU is pinned.

Before launch:

4. No idempotency on writes

Double-clicks happen. Network retries happen. Webhooks fire twice. If your “create order” endpoint can create two orders, it will.

Every mutation that matters needs either:

Stripe-style Idempotency-Key headers are not overkill for a side project. They are the difference between charging someone once and explaining to them why you charged them twice.

The stuff that breaks second

5. Auth edge cases

The AI implemented sign-up. Did it implement?

If you’re using Clerk, Supabase Auth, or Auth.js, most of this is handled but not all of it. Read the defaults.

6. Webhooks with no signature verification

Stripe, GitHub, Resend, Clerk — they all sign their webhooks. If your handler just trusts the body, anyone can POST to that URL and trigger whatever logic sits behind it. “Mark subscription as active” is a popular target.

// the line that matters
const event = stripe.webhooks.constructEvent(body, signature, secret);

If that line isn’t there, fix it before launch.

7. No error tracking

You will not know things are broken. Users do not file bug reports — they leave. Sentry has a free tier. PostHog has error tracking now. Pick one and install it. The five minutes you spend on this saves you the week where you don’t realize your signup flow has been 500ing on Safari for three days.

8. Your env vars are not actually set in production

The number of times I’ve seen a feature work locally and silently no-op in production because OPENAI_API_KEY wasn’t set in Vercel — too many. The AI cannot check this for you.

Fix: a startup check that throws loudly if required env vars are missing.

const required = ['OPENAI_API_KEY', 'DATABASE_URL', 'STRIPE_SECRET_KEY'];
for (const key of required) {
  if (!process.env[key]) throw new Error(`Missing env: ${key}`);
}

The stuff that breaks third

9. Streaming responses with no timeout

LLM streams hang. They hang on the provider side, on Cloudflare, on mobile networks. If you don’t set a timeout, your serverless function runs until the platform kills it (and bills you). Set a 60-second hard ceiling on every AI call and handle the abort gracefully.

10. Costs you cannot see

You need three numbers before launch:

If you don’t know these, you don’t know whether your pricing works. The AI will not figure this out for you. Open a spreadsheet.

11. Backups

When was the last time you tested restoring from a backup?

If the answer is “never,” you do not have backups. You have hopes. Most managed Postgres providers (Supabase, Neon, Railway) do daily snapshots, but the recovery process is something you want to have practiced once before you need it at 2am.

If you collect email, you need a privacy policy. If you take money, you need terms. The AI-generated boilerplate is fine as a starting point, but read it — it often references jurisdictions, payment processors, or data practices that don’t match what you actually do.

The honest part

I don’t always run this whole list. For a throwaway demo, I run items 1, 2, and 6. For anything with payments or user data, I run all of it.

The thing AI tools change about shipping is the cost of building, not the cost of operating. Operating a production app is the same job it was five years ago: someone has to care when it breaks at 3am, someone has to read the logs, someone has to notice the bill went up 4x.

If you’re a vibe coder shipping fast and you’ve hit the point where the app matters — has paying users, has your name on it, has real data inside it — that’s the point where a second set of eyes is worth more than another feature.

That’s what we do at EdsDev. We take things built with Cursor and Claude Code and get them to the point where they don’t wake you up. Sometimes that’s a two-day audit. Sometimes it’s a longer engagement. Either way, the checklist above is roughly where we start.

Got something running on vibes and prayers? Let’s talk.

Related posts