Methodology. Steps below follow the Vercel docs and the Next.js production checklist. The configuration files are extracted from production SaaS deploys on App Router (Next.js 14+) projects. For pricing context see Vercel pricing explained.

Deploying a Next.js SaaS to Vercel is fast, but “fast” is different from “production-ready.” A clean deploy that ships a leaked secret, an unpooled database connection, or a missing security header is worse than no deploy at all. This tutorial walks the full pre-deploy audit, the deploy itself, and the post-deploy verification checklist that catches the issues you shipped without realizing it.

Pre-deploy checklist (10 items)

Run this list before you click “Deploy.” Each item takes between two and ten minutes; collectively, they prevent the most common day-one production bugs.

  1. Env vars audit. List every process.env.X usage and confirm each will be set in Vercel. grep -r "process.env" src/ is the fastest way.
  2. No client-side secrets. Any var prefixed with NEXT_PUBLIC_ is shipped to the browser. Never put service-role keys, API secrets, or webhook secrets behind that prefix.
  3. Build without errors. Run next build locally with production env vars set. Vercel runs the same command — if it fails locally, it will fail on deploy.
  4. Lint and typecheck pass. next lint and tsc --noEmit. Don’t ship a build that you only got green by setting ignoreBuildErrors: true.
  5. Database connection pooled. Serverless functions cold-start — a non-pooled Postgres connection will exhaust your DB’s connection limit within hours. Use Supabase’s pooled connection string (port 6543) or a service like PgBouncer.
  6. Image optimization configured. Add allowed remote patterns to next.config.js for any external image hosts. Without this, <Image> components fail in production.
  7. Headers and security middleware. CSP, HSTS, X-Frame-Options — either via next.config.js headers or via middleware.ts. Sample below.
  8. sitemap.xml. App Router supports app/sitemap.ts — generate it dynamically from your routes.
  9. robots.txt. App Router supports app/robots.ts. Don’t accidentally Disallow: / on production.
  10. Error tracking. Wire up Sentry, Highlight, or PostHog before launch — not after the first 500 hits a paying user.

Sample next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  images: {
    remotePatterns: [
      { protocol: 'https', hostname: 'avatars.githubusercontent.com' },
      { protocol: 'https', hostname: 'res.cloudinary.com' }
    ]
  },
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          { key: 'X-Frame-Options', value: 'DENY' },
          { key: 'X-Content-Type-Options', value: 'nosniff' },
          { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
          { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' }
        ]
      }
    ];
  }
};
module.exports = nextConfig;

Sample middleware.ts

import { NextResponse, type NextRequest } from 'next/server';

export function middleware(req: NextRequest) {
  const res = NextResponse.next();

  // basic CSP — adjust connect-src for your APIs
  res.headers.set(
    'Content-Security-Policy',
    "default-src 'self'; script-src 'self' 'unsafe-inline' https://va.vercel-scripts.com; " +
    "style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; " +
    "connect-src 'self' https://*.supabase.co https://api.stripe.com;"
  );

  return res;
}

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)']
};

1 Connect your GitHub repository

From the Vercel dashboard, click Add New → Project and select your GitHub repo. Vercel auto-detects the Next.js framework and pre-fills the build command (next build) and output directory. Pick the production branch — usually main — and leave preview deploys enabled for all other branches and pull requests.

If your repo is in a monorepo, set the “Root Directory” to the path of the Next.js app. Vercel will run installs and builds from that directory only. For a comparison of platforms before you commit, see Vercel vs Railway.

2 Set environment variables

Vercel scopes env vars three ways: Production, Preview, and Development. Most secrets should be set on all three; some — like a separate test Stripe key — should only exist in Preview and Development.

# Required for almost every Next.js SaaS
NEXT_PUBLIC_SUPABASE_URL=https://xxxxxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGci...   # server-side only

# Stripe
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...

# App
NEXT_PUBLIC_SITE_URL=https://www.example.com
DATABASE_URL=postgres://user:pass@host:6543/db?pgbouncer=true

Add them via the dashboard (Project Settings → Environment Variables) or with the Vercel CLI:

vercel env add SUPABASE_SERVICE_ROLE_KEY production
vercel env pull .env.local   # sync down for local dev

Critical: anything ending up in the browser must be prefixed NEXT_PUBLIC_. Anything not meant for the browser must not be. There is no third option.

3 Configure your custom domain

From Project Settings → Domains, add both the apex (example.com) and the www subdomain. Vercel will show DNS records to add at your registrar — typically an A record on the apex pointing to 76.76.21.21 and a CNAME on www pointing to cname.vercel-dns.com.

Decide which is canonical. Most SaaS pick www because it allows CNAME flattening and avoids cookie-leakage issues across subdomains. In Vercel, set the non-canonical one to redirect to the canonical one.

Optional vercel.json for redirects

{
  "redirects": [
    { "source": "/login", "destination": "/auth/login", "permanent": true },
    { "source": "/signup", "destination": "/auth/signup", "permanent": true }
  ],
  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "no-store" }
      ]
    }
  ]
}

4 Set up preview deploys

Preview deploys are on by default — every PR gets a unique URL like https://your-app-git-feature-branch.vercel.app. Two things to confirm:

  • Preview env vars are set so previews actually run. Pointing previews at production data is a recipe for accidents — use a separate Supabase project for staging.
  • The Vercel GitHub integration comments the preview URL on each PR. If it doesn’t, reinstall the GitHub app from Account Settings → Integrations.

5 Configure ISR and revalidation

App Router uses tagged fetches and revalidatePath/revalidateTag for ISR. Mark cacheable fetches with a tag, then revalidate from a server action when the underlying data changes.

// src/app/blog/[slug]/page.tsx
export const revalidate = 3600; // hourly fallback

export default async function Post({ params }: { params: { slug: string } }) {
  const res = await fetch(`${process.env.API_URL}/posts/${params.slug}`, {
    next: { tags: [`post:${params.slug}`], revalidate: 3600 }
  });
  const post = await res.json();
  return <article>{/* ... */}</article>;
}

// src/app/actions/publish.ts
'use server';
import { revalidateTag } from 'next/cache';
export async function publishPost(slug: string) {
  // ... write to DB
  revalidateTag(`post:${slug}`);
}

6 Enable Vercel Analytics

From Project → Analytics, turn on Web Analytics and Speed Insights. Add the components to your root layout:

// src/app/layout.tsx
import { Analytics } from '@vercel/analytics/react';
import { SpeedInsights } from '@vercel/speed-insights/next';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Analytics />
        <SpeedInsights />
      </body>
    </html>
  );
}

Web Analytics is free up to a generous monthly event count on Hobby and Pro — enough for most early-stage SaaS. Speed Insights surfaces real-user Core Web Vitals, which is the most useful production performance signal.

Post-deploy checklist (10 items)

Once the deploy is green, work through this list before you call the launch done.

  1. Test critical paths in prod. Sign up, log in, take a payment, log out. Don’t trust staging — production env vars and DNS introduce real bugs.
  2. Monitor logs. vercel logs --prod for the first hour. Watch for 500s, slow function durations, and any unexpected console output.
  3. Set up alerts. Vercel can email on failed deploys; pair it with Sentry alerts on error spikes and an uptime monitor (Better Stack or UptimeRobot) hitting /api/health.
  4. Configure spend limits. Vercel charges by function execution and bandwidth on Pro. Set spend caps from Account → Billing so a runaway loop doesn’t cost you a month’s revenue.
  5. Rotate any secrets exposed in commits. Search your git history for sk_, SUPABASE_SERVICE_ROLE, etc. If anything was ever committed, rotate it now.
  6. Schedule cron jobs. Use Vercel Cron (configured in vercel.json) for scheduled tasks. Each cron hits a route handler under app/api/cron/*.
  7. Set up DB backup. Supabase Pro includes daily backups; on the free tier, configure a pg_dump cron yourself.
  8. Verify webhooks. Send a test webhook from Stripe/Lemon Squeezy and confirm it returns 200 with a valid signature.
  9. Check Lighthouse. Run a Lighthouse audit on the production URL. Aim for >90 on Performance and Accessibility.
  10. Submit sitemap to Search Console. Verify domain ownership in Google Search Console and submit /sitemap.xml.

Sample Vercel cron in vercel.json

{
  "crons": [
    { "path": "/api/cron/cleanup-sessions", "schedule": "0 3 * * *" },
    { "path": "/api/cron/usage-report",      "schedule": "0 8 * * 1" }
  ]
}

Cron handlers should verify the Authorization: Bearer ${CRON_SECRET} header that Vercel attaches automatically.

Summary
Audit → deploy → verify

A production-grade Next.js deploy is a 30–60 minute exercise the first time, then 5 minutes after that. The pre-deploy and post-deploy checklists are the part most teams skip — and the part that catches the bugs that would otherwise burn your launch.

Related guides

Get one SaaS build breakdown every week

The stack, prompts, pricing, and mistakes to avoid — for solo founders building with AI.