Deploy to Vercel

Deploy your Next.js application to Vercel.

Prerequisites#

Quick Deploy#

Via Vercel Dashboard#

  1. Go to vercel.com/new
  2. Import your Git repository
  3. Configure environment variables
  4. Click Deploy

Via CLI#

1# Install Vercel CLI 2npm install -g vercel 3 4# Login 5vercel login 6 7# Deploy 8vercel 9 10# Deploy to production 11vercel --prod

Environment Variables#

Required Variables#

1# Database 2DATABASE_URL=postgresql://... 3 4# Authentication (Clerk) 5NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_... 6CLERK_SECRET_KEY=sk_... 7 8# Payments (Stripe) 9STRIPE_SECRET_KEY=sk_... 10NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_... 11STRIPE_WEBHOOK_SECRET=whsec_... 12 13# App URL 14NEXT_PUBLIC_APP_URL=https://your-app.vercel.app

Setting Variables via CLI#

1# Add a variable 2vercel env add DATABASE_URL 3 4# Add for specific environment 5vercel env add STRIPE_SECRET_KEY production 6 7# Pull variables to local .env 8vercel env pull .env.local

Project Configuration#

1// vercel.json 2{ 3 "framework": "nextjs", 4 "buildCommand": "prisma generate && next build", 5 "installCommand": "npm ci", 6 "regions": ["iad1"], 7 "crons": [ 8 { 9 "path": "/api/cron/cleanup", 10 "schedule": "0 0 * * *" 11 } 12 ], 13 "headers": [ 14 { 15 "source": "/api/(.*)", 16 "headers": [ 17 { 18 "key": "Cache-Control", 19 "value": "no-store" 20 } 21 ] 22 } 23 ] 24}

Database Setup (Neon)#

1. Create Neon Project#

1# Install Neon CLI 2npm install -g neonctl 3 4# Login 5neonctl auth 6 7# Create project 8neonctl projects create --name my-project

2. Get Connection String#

neonctl connection-string --project-id <project-id>

3. Configure Prisma#

1// prisma/schema.prisma 2datasource db { 3 provider = "postgresql" 4 url = env("DATABASE_URL") 5 directUrl = env("DIRECT_URL") // For migrations 6}

4. Run Migrations#

# Local development npx prisma migrate dev # Production (in CI/CD) npx prisma migrate deploy

CI/CD with GitHub Actions#

1# .github/workflows/deploy.yml 2name: Deploy to Vercel 3 4on: 5 push: 6 branches: [main] 7 pull_request: 8 branches: [main] 9 10env: 11 VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} 12 VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} 13 14jobs: 15 test: 16 runs-on: ubuntu-latest 17 steps: 18 - uses: actions/checkout@v4 19 20 - name: Setup Node.js 21 uses: actions/setup-node@v4 22 with: 23 node-version: '20' 24 cache: 'npm' 25 26 - name: Install dependencies 27 run: npm ci 28 29 - name: Run tests 30 run: npm test 31 32 - name: Run linting 33 run: npm run lint 34 35 deploy-preview: 36 needs: test 37 if: github.event_name == 'pull_request' 38 runs-on: ubuntu-latest 39 steps: 40 - uses: actions/checkout@v4 41 42 - name: Install Vercel CLI 43 run: npm install -g vercel 44 45 - name: Pull Vercel Environment 46 run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} 47 48 - name: Build 49 run: vercel build --token=${{ secrets.VERCEL_TOKEN }} 50 51 - name: Deploy Preview 52 id: deploy 53 run: | 54 url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}) 55 echo "url=$url" >> $GITHUB_OUTPUT 56 57 - name: Comment PR 58 uses: actions/github-script@v7 59 with: 60 script: | 61 github.rest.issues.createComment({ 62 issue_number: context.issue.number, 63 owner: context.repo.owner, 64 repo: context.repo.repo, 65 body: '🚀 Preview: ${{ steps.deploy.outputs.url }}' 66 }) 67 68 deploy-production: 69 needs: test 70 if: github.event_name == 'push' && github.ref == 'refs/heads/main' 71 runs-on: ubuntu-latest 72 steps: 73 - uses: actions/checkout@v4 74 75 - name: Install Vercel CLI 76 run: npm install -g vercel 77 78 - name: Pull Vercel Environment 79 run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} 80 81 - name: Build 82 run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} 83 84 - name: Run Migrations 85 env: 86 DATABASE_URL: ${{ secrets.DATABASE_URL }} 87 run: npx prisma migrate deploy 88 89 - name: Deploy Production 90 run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}

Domain Configuration#

Add Custom Domain#

# Add domain vercel domains add yourdomain.com # Verify vercel domains verify yourdomain.com

DNS Configuration#

Add these records to your DNS provider:

TypeNameValue
A@76.76.21.21
CNAMEwwwcname.vercel-dns.com

Edge Functions#

1// app/api/edge/route.ts 2export const runtime = 'edge'; 3 4export async function GET(request: Request) { 5 return new Response('Hello from the Edge!', { 6 headers: { 7 'x-edge-region': request.headers.get('x-vercel-ip-country') || 'unknown', 8 }, 9 }); 10}

Middleware#

1// middleware.ts 2import { NextResponse } from 'next/server'; 3import type { NextRequest } from 'next/server'; 4 5export function middleware(request: NextRequest) { 6 // Add geo-location headers 7 const response = NextResponse.next(); 8 9 response.headers.set( 10 'x-user-country', 11 request.geo?.country || 'unknown' 12 ); 13 14 return response; 15} 16 17export const config = { 18 matcher: '/api/:path*', 19};

Monitoring#

Enable Analytics#

1// app/layout.tsx 2import { Analytics } from '@vercel/analytics/react'; 3import { SpeedInsights } from '@vercel/speed-insights/next'; 4 5export default function RootLayout({ children }) { 6 return ( 7 <html> 8 <body> 9 {children} 10 <Analytics /> 11 <SpeedInsights /> 12 </body> 13 </html> 14 ); 15}

Error Tracking with Sentry#

npx @sentry/wizard@latest -i nextjs

Rollback#

# List deployments vercel ls # Rollback to specific deployment vercel rollback <deployment-url>