How do I deploy a vibe-coded app to Vercel and Supabase?
Connect the GitHub repo to Vercel, set every environment variable for Production and Preview before the first build, and apply your Supabase migrations to the production project with supabase db push. Then switch Stripe to live keys with a live webhook endpoint, add your custom domain, and point the Supabase Site URL at it. Vercel applies env var changes only to new deployments, so redeploy after each change.
Why this matters
Locally your app has one database, one set of keys and one URL. A deploy gives it at least two of each: Vercel builds a preview deployment for each push to another branch and a production deployment from your production branch, Stripe has a sandbox and live mode, and Supabase may have a development project next to production. A deploy goes wrong when one of those pairs points at the wrong half, such as a production build with sandbox Stripe keys, or a preview build writing to the production database.
Deploy in this order
- Push the repo to GitHub and import it into Vercel from the dashboard. From then on Vercel deploys by itself: a preview deployment for each push to another branch, and a production deployment for each merge to the production branch, usually main.
- Before the first production build, add every variable the code reads in the Vercel project settings, choosing Production, Preview or Development for each. In Next.js only variables prefixed NEXT_PUBLIC_ reach the browser, so secret keys must not carry that prefix. From the CLI:
vercel env add STRIPE_SECRET_KEY production vercel env ls production - Decide what Preview talks to. If preview deployments use your production Supabase project, every branch can write real user data. Use a second Supabase project for Preview, or Supabase branching, which gives each branch its own instance and API credentials and starts it without your production data.
- Apply your migrations to production from the CLI, not by editing tables in the dashboard. Supabase's golden rule is to never change the remote database directly once you use migrations, because it bypasses the migration history and makes db push fail. See what is applied first:
supabase link --project-ref YOUR_PROJECT_REF supabase migration list supabase db push - In Supabase, under Authentication and then URL Configuration, change the Site URL from http://localhost:3000 to your production URL. Add http://localhost:3000/** and https://*-<team-or-account-slug>.vercel.app/** as redirect URLs, the patterns Supabase gives for local development and Vercel previews.
- Switch Stripe to live mode for Production only: live keys in the Production environment, sandbox keys in Preview. Recreate the products and prices you need in live mode, because Stripe says sandbox objects are not usable there, and check that the IDs your code reads match the live ones.
- Register a live webhook endpoint at your production URL. Stripe generates a unique signing secret for each endpoint, so the live whsec_ value goes in Production as your webhook secret; with the sandbox secret, every live event fails verification.
- Add your custom domain under Settings, then Domains: an A record for an apex domain such as example.com, a CNAME for a subdomain. If you move your nameservers to Vercel, copy your DNS records first, including MX records for email. Then update the Supabase Site URL, and the Stripe webhook URL if you registered it on the vercel.app address.
- Redeploy, then test the production URL as a new user: sign up, confirm the email, make one real purchase and refund it, and check that the webhook was delivered. If it breaks, Vercel's Instant Rollback puts the previous production deployment back; on the Hobby plan, only the one immediately before.
What goes where: Production, Preview and local
One block per setting that has to differ between environments.
The Supabase project
Production: your production project. Preview: a second project or a Supabase branch. Local: supabase start, which runs the stack on your machine and prints a publishable key and a secret key for it.
Stripe keys and the webhook secret
Production: live keys and the live endpoint's whsec_ secret. Preview: sandbox keys and a sandbox endpoint's secret. Local: sandbox keys and the signing secret that stripe listen prints; Stripe warns not to verify events forwarded by the CLI with a Dashboard endpoint's secret, or the other way around.
Auth redirect URLs
Production: the Site URL is your domain. Preview: a wildcard entry for your Vercel preview URLs. Local: http://localhost:3000/**. Supabase recommends the exact redirect path, not a wildcard, for production.
The site URL your code builds links from
Supabase's redirect guide builds redirect links from NEXT_PUBLIC_SITE_URL, set to your domain in Production, and falls back to NEXT_PUBLIC_VERCEL_URL, which Vercel sets for each deployment. Everything else that differs, such as API keys and database URLs, gets one value per environment in Vercel.
Optional repo check
For AI-built Vercel + Supabase apps, npx -y viberaven@1.6.3 check is a pre-deploy review for vibe-coded Vercel + Supabase apps that reads the repo before step 2. In a run on a fixture repo on 2026-10-05 it listed env vars the code reads that .env.example does not document (OPENAI_API_KEY and SUPABASE_SERVICE_ROLE_KEY), NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY in .env.example, and a Stripe webhook handler with no signature check. It cannot see the variables set in your Vercel project, which migrations production has applied, your Supabase URL settings or your Stripe dashboard, so the other steps stay with you. It is advice, not a gate, and a repository check, not a live database or security test. It exits with code 1 when it finds a blocker and writes a .viberaven folder that it does not add to .gitignore.
Related guides
- I vibe coded an app. Now what?
- How do I secure a vibe-coded app?
- Vercel Environment Variables Checklist for AI Apps
- Vercel Preview to Production Checklist
- Stripe Live Mode Checklist for AI-Built Apps
- Stripe webhook works locally but fails after deploy: how to diagnose and fix it
- Production env var drift in AI-built apps: how to find what differs between local, preview and production
Sources
- Vercel, Deploying Git repositories with Vercel
- Vercel, Environments
- Vercel, Environment variables
- Vercel, vercel env
- Next.js, Environment variables
- Supabase, Branching
- Supabase, Database migrations
- Supabase CLI, supabase link
- Supabase, Redirect URLs
- Supabase, API keys
- Stripe, Go-live checklist
- Stripe, Receive Stripe events in your webhook endpoint
- Stripe, Resolve webhook signature verification errors
- Vercel, Adding and configuring a custom domain
- Vercel, Instant Rollback
Why does my app work locally but not on Vercel?
Often a variable exists in .env.local but not in the Vercel project, is set for Preview but not Production, or was changed after the last deployment, since Vercel applies env var changes only to new deployments. Check the build and runtime logs for the first undefined value.
Do I need a separate Supabase project for preview deployments?
Not to launch, but it is the plain way to keep preview deployments away from real user data. Supabase branching is the managed alternative: each branch gets its own instance and credentials, and starts without production data unless you seed it.
Should I deploy with the Vercel CLI or from GitHub?
Either works. Connecting GitHub gives you a preview deployment for each push to another branch and a production deployment for each merge to the production branch; vercel --prod creates a production deployment from your machine.