AI Founder OS
Shipping

Shipping checklists

Localhost is not production. These checklists close the gap between "it works on my machine" and "it works for real users on real devices."

Operator loop: 6-step cycle from define to ship1Define goal2Draft spec3Execute4Handoff5Verify6Ship

Ship pipeline

Verify. Build. Deploy. Confirm. Monitor. Repeat.

What production parity means

Your local environment lies to you in predictable ways. Production parity means eliminating these mismatches before users find them.

  • Environment variables differ between local and production. A key that exists in .env.local may be missing from your hosting dashboard.
  • Dependencies resolve differently. A package that works locally because of a hoisted peer dependency may fail in a clean production install.
  • Runtime behavior changes. Edge functions, serverless cold starts, and CDN caching do not exist on localhost.
  • Client caches persist across deploys. A user may see stale JavaScript bundles unless cache headers are handled correctly.
  • Device lanes are not interchangeable. A web deploy does not prove the mobile build works, and a simulator run does not prove TestFlight works.

Anti-pattern

The most common shipping failure is a missing environment variable. The build passes because the variable is only read at runtime. The deploy succeeds. Then every page returns a 500. Check your hosting dashboard before every deploy.

Web lane checklist (Vercel)

Use this for every web deploy. Each step has a concrete check you can verify before and after pushing.

A. Before deploy

Confirm every required env var exists in your Vercel project settings. Pay special attention to NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY. If either is missing, prerender will fail with a cryptic error.

Check dependency parity. If a file imports a package, that package must be in dependencies in package.json. The build will succeed locally if the package is hoisted, but fail in production where the install is clean.

Confirm which branch is your production branch in Vercel project settings. If you are deploying from main, verify that main is set as the production branch, not a preview branch.

B. Deploy and confirm

After pushing, open the Vercel deployment. Confirm the deployment commit SHA matches the commit you just pushed. If it does not match, the deploy may have triggered from a stale push or a different branch.

Verify the correct domain is attached to the correct Vercel project. If you have multiple projects (staging, production), confirm the live domain points to the production project, not a preview or test project.

Open the deployed URL in an incognito window. Check that pages load, auth flows work, and dynamic routes return data. Do not trust a cached browser session.

C. Rollback and recovery

If a deploy breaks production, redeploy the previous successful deployment from the Vercel dashboard. Do not push a hasty fix. Revert first, investigate second.

Keep one verified fix per deploy. If you bundle multiple fixes into one push and something breaks, you cannot tell which fix caused the failure. Ship one change, confirm it works, then ship the next.

Mobile lane checklist (Expo / React Native)

The mobile lane has more steps because more things can silently diverge. A green simulator build does not mean the production binary works.

A. Before shipping

The simulator is not TestFlight. The simulator runs a debug build with developer tools enabled, hot reload active, and no signing. TestFlight runs a release build with production signing, no dev menu, and real push notification entitlements. Testing only in the simulator leaves an entire class of bugs undiscovered.

Know what triggers a native rebuild. Changes to app.json or app.config.js, adding or removing config plugins, changing the app icon or splash screen, modifying iOS entitlements or Android permissions all require a fresh native build. A JavaScript-only update will not pick up these changes.

Run a prebuild clean before shipping. Use npx expo prebuild --clean (Expo) or delete the ios/ and android/ folders and regenerate them. Stale native artifacts from previous builds can cause signing errors or crash-on-launch bugs that only appear in production.

B. Proof lane

Simulator run proof (minimum bar)

  • App launches without crash on iOS simulator and Android emulator
  • All core screens render with real or mock data
  • Navigation between screens works without blank frames
  • No red screen errors or yellow box warnings in the console

TestFlight proof checklist (required before App Store)

  • Install from TestFlight on a real device (not an upgrade, a fresh install)
  • Complete the full auth flow: sign up, sign in, sign out, sign back in
  • Open every core screen and confirm content loads
  • Test on at least one older device or OS version you support
  • Confirm push notifications arrive if the app uses them
  • Check that the app version and build number are correct in Settings

C. Shipping discipline

One change per build when stabilizing. If you are fixing a crash, do not also add a feature. Ship the fix, confirm it works in TestFlight, then ship the feature separately. Mixing changes makes it impossible to isolate which change caused a new problem.

Require handoff proofs for every mobile build. The handoff must include the exact git commit SHA, the build number, the verification steps performed, and the literal output of git show --stat HEAD. If there is no proof, the build is not shippable.

Common shipping failures

Six failures that come up repeatedly. Each one has a short explanation and a fix.

Deploy succeeds but pages return 500 errors

Cause: A required environment variable is missing from the hosting dashboard. The build compiles fine because the variable is only read at runtime.

Fix: Compare every key in .env.local against the hosting dashboard. Add any missing keys and redeploy.

Build fails in production but passes locally

Cause: A dependency is imported but not listed in package.json. It works locally because another package hoists it, but the production install is clean and does not have it.

Fix: Run npm ls [package-name] locally. If it shows as a peer or transitive dependency, add it explicitly to dependencies.

Live site shows old content after deploy

Cause: The domain is attached to the wrong Vercel project, or a preview deployment is being served instead of the production deployment.

Fix: Open Vercel project settings. Confirm the production domain points to the correct project and the correct branch.

You deploy but the site looks unchanged

Cause: The browser is serving a cached version of the JavaScript bundle. Or the deployment triggered from a stale commit, not your latest push.

Fix: Check the deployment commit SHA in the Vercel dashboard. Open the site in an incognito window. If the SHA is wrong, check which branch triggered the deploy.

Web works but mobile app crashes on launch

Cause: A native dependency was updated or a config plugin changed, but the native binary was not rebuilt. The JavaScript bundle expects native modules that do not exist in the installed binary.

Fix: Run a prebuild clean and rebuild the native binary. Install the fresh build on a simulator and confirm it launches before submitting to TestFlight.

TestFlight build works but App Store review rejects it

Cause: The app uses a permission or entitlement that was not declared in the store listing, or the privacy policy URL is missing or broken.

Fix: Review the App Store Connect submission checklist. Confirm every permission has a usage description, the privacy policy URL loads, and screenshots match the current build.