Vercel Logo

Deploy to Production

Test mode was training wheels. Production mode processes real payments with real money. This lesson walks through switching from test keys to live keys, configuring production environment variables, and verifying the complete subscription flow works end-to-end.

Outcome

Deploy your storefront to production with live Stripe payments and verify the complete user journey.

Fast Track

  1. Get production keys from Stripe and Supabase dashboards
  2. Add production environment variables in Vercel
  3. Deploy and test with a real card (then refund)

Hands-on Exercise 4.3

Deploy to production:

Requirements:

  1. Create or switch to production Stripe keys
  2. Configure production Supabase project
  3. Add all environment variables in Vercel dashboard
  4. Deploy to production
  5. Test complete flow: sign up → subscribe → access premium → cancel

Implementation hints:

  • Stripe live keys start with sk_live_ and pk_live_
  • Create a separate Supabase project for production (recommended)
  • Stripe webhooks need production URLs
  • Test with a real card, then immediately refund

Environment variables needed:

NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
STRIPE_SECRET_KEY
STRIPE_WEBHOOK_SECRET

Try It

  1. Deploy to Vercel:

    git push origin main

    Or trigger deploy from Vercel dashboard.

  2. Test sign up:

    • Visit your production URL
    • Create a new account
    • Verify email confirmation works
  3. Test subscription:

    • Navigate to pricing page
    • Select a plan and checkout
    • Use a real card (you'll refund it)
    • Verify redirect to subscription page
  4. Test premium access:

    • Visit premium features page
    • Generate a cat photo
    • Verify entitlement check passes
  5. Test cancellation:

    • Cancel subscription from subscription page
    • Verify status changes to "cancelling"
  6. Refund the charge:

    • Go to Stripe dashboard → Payments
    • Find your test payment
    • Issue full refund

Commit

No code changes in this lesson—configuration only.

Done-When

  • Production Stripe keys in Vercel
  • Production Supabase credentials in Vercel
  • Stripe webhook configured for production URL
  • Deployed successfully to production
  • Sign up flow works
  • Subscription checkout works with real card
  • Premium features accessible after subscription
  • Cancellation flow works
  • Test payment refunded

Solution

Step 1: Get Production Stripe Keys

  1. Go to Stripe Dashboard
  2. Toggle off "Test mode" in the sidebar (or click "Activate your account" if first time)
  3. Complete account verification if prompted
  4. Go to Developers → API keys
  5. Copy your live keys:
    • Publishable key: pk_live_...
    • Secret key: sk_live_...

Step 2: Create Production Stripe Products

Your test mode products don't transfer to live mode. Create them again:

  1. In Stripe dashboard (live mode), go to Products
  2. Create the same products you had in test mode:
    • Basic Plan: $9/month
    • Pro Plan: $29/month
  3. Copy the new price IDs

Step 3: Configure Stripe Webhook

  1. Go to Developers → Webhooks
  2. Click Add endpoint
  3. Enter your production URL:
    https://your-app.vercel.app/api/webhooks/stripe
    
  4. Select events to listen for:
    • checkout.session.completed
    • customer.subscription.updated
    • customer.subscription.deleted
  5. Click Add endpoint
  6. Copy the webhook signing secret: whsec_...

Step 4: Set Up Production Supabase

Option A: Use same project (simpler, less isolated):

  • Keep using your existing Supabase project
  • Production and development share the same database

Option B: Create new project (recommended for real apps):

  1. Go to Supabase Dashboard
  2. Click New Project
  3. Name it storefront-production
  4. Choose a strong database password
  5. Select a region close to your users
  6. Wait for project to provision
  7. Go to Settings → API and copy:
    • Project URL
    • anon public key

If using Option B, also configure auth:

  1. Go to Authentication → URL Configuration
  2. Set Site URL to your production domain
  3. Add redirect URLs for your production domain

Step 5: Add Environment Variables in Vercel

  1. Go to Vercel Dashboard
  2. Select your project
  3. Go to Settings → Environment Variables
  4. Add each variable for Production environment:
VariableValueEnvironment
NEXT_PUBLIC_SUPABASE_URLhttps://xxx.supabase.coProduction
NEXT_PUBLIC_SUPABASE_ANON_KEYeyJ...Production
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYpk_live_...Production
STRIPE_SECRET_KEYsk_live_...Production
STRIPE_WEBHOOK_SECRETwhsec_...Production
  1. Click Save for each variable

Step 6: Deploy

Trigger a new deployment to pick up the environment variables:

git commit --allow-empty -m "chore: trigger production deploy"
git push origin main

Or in Vercel dashboard: Deployments → Redeploy

Step 7: Verify Deployment

  1. Check build logs:

    • Go to Vercel dashboard → Deployments
    • Click latest deployment
    • Verify build succeeded
  2. Check environment:

    • In deployment details, verify environment variables loaded
    • Check for any build warnings
  3. Test the live site:

    • Visit your production URL
    • Verify pages load without errors
    • Check browser console for issues

Step 8: End-to-End Test

Perform a complete user journey:

  1. Sign up:

    • Create new account with real email
    • Confirm email if required
    • Verify redirect to protected area
  2. Subscribe:

    • Navigate to pricing
    • Click subscribe on a plan
    • Complete checkout with real card:
      • Card: Your actual card
      • Or use Stripe test card if still in test mode
    • Verify redirect to subscription page
    • Verify subscription shows as active
  3. Access premium:

    • Navigate to premium features
    • Generate a cat photo
    • Verify it works
  4. Cancel:

    • Click cancel on subscription page
    • Verify status changes
  5. Refund (important!):

    • Go to Stripe dashboard
    • Find the payment
    • Click RefundFull refund
    • Confirm refund

Production Checklist

Before announcing your launch:

Authentication
- [ ] Sign up works with email confirmation
- [ ] Sign in works
- [ ] Sign out works
- [ ] Password reset works (if implemented)

Billing
- [ ] Pricing page shows correct prices
- [ ] Checkout redirects to Stripe
- [ ] Webhook processes successfully
- [ ] Subscription shows after checkout
- [ ] Cancel/reactivate works

Access Control
- [ ] Premium features blocked without subscription
- [ ] Premium features accessible with subscription
- [ ] Entitlement checks work correctly

Error Handling
- [ ] Error pages display correctly
- [ ] Loading states appear
- [ ] API errors handled gracefully

Performance
- [ ] Pages load in <3 seconds
- [ ] No console errors
- [ ] Images optimized

Environment Variable Reference

VariableWhere to GetUsed For
NEXT_PUBLIC_SUPABASE_URLSupabase → Settings → APIAuth, database
NEXT_PUBLIC_SUPABASE_ANON_KEYSupabase → Settings → APIClient auth
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYStripe → Developers → API KeysClient billing
STRIPE_SECRET_KEYStripe → Developers → API KeysServer billing
STRIPE_WEBHOOK_SECRETStripe → Developers → WebhooksWebhook verification

Troubleshooting

Checkout fails in production:

  • Verify Stripe live keys are set (not test keys)
  • Check Stripe dashboard for error logs
  • Verify products exist in live mode

Webhook not working:

  • Verify webhook URL is correct in Stripe
  • Check webhook secret matches environment variable
  • Look at Stripe webhook logs for delivery status
  • Test with Stripe CLI: stripe listen --forward-to localhost:3000/api/webhooks/stripe

Auth not working:

  • Verify Supabase URL and keys are correct
  • Check Supabase auth settings for production URL
  • Verify redirect URLs include production domain
  • Check email templates are configured

"Invalid API key" errors:

  • Environment variables may not have reloaded
  • Redeploy to pick up new variables
  • Verify no typos in variable names
  • Check variables are set for Production environment (not just Preview)

Subscription shows but access control doesn't work:

  • Check that price IDs in your code match live mode (not test mode)
  • Verify hasActiveSubscription checks are using the correct Stripe subscription status
  • Check browser console for API errors when loading subscription data

What's Next

Congratulations! You've built and deployed a complete subscription storefront with:

  • User authentication with Supabase
  • Subscription billing with Stripe
  • Subscription-based access control
  • Production-ready error handling and loading states
  • Complete navigation and UI

Potential enhancements:

  • Add more subscription tiers
  • Implement usage-based billing
  • Add team/organization features
  • Build admin dashboard
  • Add analytics tracking
  • Implement email notifications

You now have a solid foundation for any subscription-based SaaS product.