DEV Community

Atlas Whoff
Atlas Whoff

Posted on

Production Deployment Checklist: Migrations, Webhooks, Feature Flags, and Rollbacks

The Deployment That Breaks Production

It's 2 AM. You deployed 4 hours ago. Stripe webhooks are failing.
Your database migration didn't run. Users can't subscribe.

This is preventable. Here's the deployment checklist that catches it.

Before Every Deploy

# 1. Verify tests pass
npm test

# 2. Verify build succeeds
npm run build

# 3. Verify TypeScript (if not part of build)
npx tsc --noEmit

# 4. Check for known vulnerabilities
npm audit --audit-level=high

# 5. Verify environment variables are set in Vercel
vercel env ls
Enter fullscreen mode Exit fullscreen mode

Database Migration Strategy

# CI/CD: run migrations BEFORE deploying new code
# This ensures DB schema is ready when new code starts

# .github/workflows/deploy.yml
jobs:
  deploy:
    steps:
      - name: Run migrations
        run: npx prisma migrate deploy  # Production-safe
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}

      - name: Deploy to Vercel
        run: vercel --prod
        # Deploys AFTER migrations are complete
Enter fullscreen mode Exit fullscreen mode

Stripe Webhook Verification

# After every deploy, verify webhooks are configured correctly
# In Stripe Dashboard -> Webhooks -> your endpoint
# Check: endpoint URL matches your current deployment URL
# Check: webhook secret in Vercel env matches Stripe dashboard
# Test: 'Send test webhook' and verify 200 response

# Most common webhook failures after deploy:
# 1. STRIPE_WEBHOOK_SECRET not updated after rotating
# 2. Endpoint URL still pointing to old deployment
# 3. Raw body not preserved (req.json() instead of req.text())
Enter fullscreen mode Exit fullscreen mode

Feature Flags for Safe Deploys

// Deploy code behind a flag -- enable separately from deploy
import { get } from '@vercel/edge-config'

const newBillingEnabled = await get<boolean>('new-billing-flow')

if (newBillingEnabled) {
  return <NewBillingFlow />
}
return <OldBillingFlow />

// Now you can:
// 1. Deploy code (flag off = old behavior)
// 2. Test in production with your own account
// 3. Enable flag for 10% of users
// 4. Monitor for errors
// 5. Roll out to 100%
Enter fullscreen mode Exit fullscreen mode

Rollback Strategy

# Vercel: instant rollback to previous deployment
vercel rollback

# Or in Vercel dashboard: Deployments -> previous deploy -> 'Promote to Production'

# Database rollback: harder
# Prevention: additive-only migrations in production
# - Add columns, don't drop them
# - Add tables, don't remove them
# - Make columns nullable before removing
# (Destructive changes only after code no longer references the field)
Enter fullscreen mode Exit fullscreen mode

Post-Deploy Smoke Test

#!/bin/bash
# scripts/smoke-test.sh
BASE_URL=${1:-https://yourapp.com}

# Check homepage
STATUS=$(curl -s -o /dev/null -w '%{http_code}' "$BASE_URL")
[ "$STATUS" -eq 200 ] && echo 'Homepage: OK' || echo "Homepage: FAIL ($STATUS)"

# Check API health
STATUS=$(curl -s -o /dev/null -w '%{http_code}' "$BASE_URL/api/health")
[ "$STATUS" -eq 200 ] && echo 'API: OK' || echo "API: FAIL ($STATUS)"

# Run after every production deploy
Enter fullscreen mode Exit fullscreen mode

The Health Endpoint

// app/api/health/route.ts
import { db } from '@/lib/db'

export async function GET() {
  try {
    // Check DB connection
    await db.$queryRaw`SELECT 1`

    return Response.json({
      status: 'ok',
      timestamp: new Date().toISOString(),
      version: process.env.VERCEL_GIT_COMMIT_SHA?.slice(0, 7) ?? 'dev'
    })
  } catch (error) {
    return Response.json(
      { status: 'error', message: 'DB connection failed' },
      { status: 503 }
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

Pre-Configured Deploy Pipeline

The AI SaaS Starter Kit includes GitHub Actions CI/CD, health endpoint, smoke test script, and migration-before-deploy workflow.

$99 one-time at whoffagents.com

Top comments (0)