Skip to Content
Deploy to Vercel

Deploy to Vercel

Production is mostly an env-parity problem.

The most common mistake is getting Vercel, Clerk, Convex, and Stripe individually “working” while the cross-system values still drift.

Before the first deploy

Prepare production values in your hosting dashboards and provider dashboards. Mirror the same categories you use locally and verify they match across systems:

  • Clerk publishable and secret keys
  • Clerk frontend API URL
  • Convex client URL (NEXT_PUBLIC_CONVEX_URL)
  • Convex HTTP-actions URL (NEXT_PUBLIC_CONVEX_SITE_URL) when the deployment serves HTTP actions on .convex.site
  • any deployment values your Convex environment writes
  • Stripe secret key, product id, price id
  • live STRIPE_WEBHOOK_SECRET
  • APP_BASE_URL
  • OBSERVABILITY_INGEST_TOKEN
  • OBSERVABILITY_INCIDENT_CONTROL_TOKEN
  • CLERK_WEBHOOK_SIGNING_SECRET
  • OBSERVABILITY_VERCEL_WEBHOOK_SECRET
  • TELEGRAM_BOT_TOKEN
  • TELEGRAM_CHAT_ID

Vercel checklist

  • deploy as a normal Next.js app
  • keep the project linked to ParkerRex/mma-shipbysunday
  • keep Vercel’s production branch on main
  • let Preview continue to handle unassigned git branches such as dev and feature branches
  • keep the package manager pinned to the repo version
  • use real production Clerk env values
  • use real production Stripe live keys
  • if the app uses observability or any other Convex HTTP actions, set NEXT_PUBLIC_CONVEX_SITE_URL to the matching .convex.site host

Do not make Vercel responsible for production Convex deploys in this repo. The frontend should build on Vercel, but Convex production promotion now happens from GitHub Actions on main through .github/workflows/convex-production-deploy.yml.

CONVEX_DEPLOY_KEY belongs in GitHub repository secrets for that workflow, not in the Vercel project.

Convex checklist

Convex production must match the same production auth and Stripe values used by the app.

Do not leave Convex pointed at:

  • an old Clerk instance
  • a dev Clerk instance
  • an outdated Stripe webhook secret
  • a mismatched Stripe secret key
  • a deployment that does not have the current observability functions pushed

Post-deploy verification

After a release merge to main, confirm all of this with a real test flow:

  1. signed-out visitor hits a protected route and is pushed to sign-in
  2. signed-in user without access reaches /start and sees inline recovery
  3. live checkout returns to /checkout/success
  4. webhook grants access
  5. newly granted user reaches /start
  6. signed Clerk and Vercel observability webhooks persist incidents and deliver Telegram packets
  7. the public incident status route can ack a live incident and keep repeat delivery suppressed
  8. Vercel attributes the production web deploy to main
  9. GitHub Actions reports a matching Convex Production Deploy run for the same release

Use the QA control-plane command for the authenticated production pass:

PLAYWRIGHT_BASE_URL=https://www.man-meets-ai.com QA_ENV_FILE=apps/web/.env.production bun run qa:run-pack -- --pack=default_ship

That command assumes:

  • qa/personas.local.json contains the real QA account emails and passwords
  • the file referenced by QA_ENV_FILE contains the production Clerk and Convex env values
  • the production Clerk instance matches the target site

If persona prep fails with a Clerk publishable-key mismatch, stop there. That means the loaded env file does not match the production site, so any later authenticated browser result would be invalid.

What success looks like

Production is healthy when payment, access, route protection, observability, and deployment provenance all agree on the same release. In this repo that means the web app came from Vercel main, the backend came from the Convex production workflow on main, and both use the same production env values.

If payment completes but access does not, debug env parity before you rewrite application code.

Last updated on