Deploying React and Next.js Apps to Vercel: Step-by-Step Production Guide
Deploying a React or Next.js app to production should be fast, reliable, and reproducible. Here is the step-by-step guide to configuring Vercel with custom domains, strict headers, preview deployments, and optimal performance.
Vercel is the primary cloud platform built by the creators of Next.js, and for good reason: it offers seamless continuous integration, global edge caching, preview environments on every Git branch, and zero-configuration serverless execution.
However, moving from a simple hobby deploy to a hardened production application requires attention to security headers, environment isolation, custom domain DNS, and build performance.
In this guide, I share the production checklist and step-by-step workflow I use to deploy client applications to Vercel with optimal speed and security.
Step 1: Connecting Your Git Repository
The most reliable way to manage Vercel deployments is through Git integration (GitHub, GitLab, or Bitbucket):
- Sign in to your Vercel Dashboard.
- Click "Add New..." ➔ "Project".
- Import your Git repository.
- Select your framework preset (e.g. Next.js or Vite). Vercel automatically detects build commands (
npm run build) and output directories (.nextordist).
Step 2: Environment Variable Configuration and Security
Never hardcode API keys or database URLs into your repository. Vercel allows you to scope environment variables across three distinct environments:
- Production: Applied to the main branch (
mainormaster). - Preview: Applied to pull requests and feature branches.
- Development: Pulled locally using
vercel env pull.
Crucial Security Rule for Next.js:
Variables prefixed with NEXT_PUBLIC_ are embedded into the client-side JavaScript bundle and are visible to anyone inspecting the browser source code.
- Public:
NEXT_PUBLIC_SITE_URL,NEXT_PUBLIC_SUPABASE_URL,NEXT_PUBLIC_SUPABASE_ANON_KEY - Secret (Server Only):
SUPABASE_SERVICE_ROLE_KEY,DATABASE_URL,RESEND_API_KEY,STRIPE_SECRET_KEY
Ensure that all secret keys are added without the NEXT_PUBLIC_ prefix so they remain strictly on the server.
Step 3: Hardening Security Headers in next.config.js
By default, web browsers permit framing and MIME sniffing unless explicitly restricted. Add production security headers to your next.config.js file:
/** @type {import('next').NextConfig} */ const nextConfig = { 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: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()", }, ], }, ]; }, }; module.exports = nextConfig;
Step 4: Connecting Custom Domains and DNS Records
To connect your custom domain (e.g. bahaj.dev):
- Navigate to Project Settings ➔ Domains.
- Enter your root domain and the
wwwsubdomain. - Configure your DNS records at your registrar (Cloudflare, Namecheap, GoDaddy):
- Root domain (
@): A record pointing to76.76.21.21 - Subdomain (
www): CNAME record pointing tocname.vercel-dns.com
- Root domain (
Vercel automatically issues and renews Let's Encrypt SSL certificates within minutes of DNS verification.
Step 5: Optimizing Build Time and Caching
Long build times slow down deployment pipelines. Keep your builds fast:
- Prune unused packages: Audit
package.jsondependencies periodically. - Enable Incremental Static Regeneration (ISR): Render static pages at build time and revalidate them in the background without requiring a full site rebuild.
- Next.js Image Optimization: Use
next/imageto automatically serve WebP/AVIF images sized for the user's viewport.
For post-deployment verification and Core Web Vitals checks, review my Pre-Launch Website Audit Checklist and How to Read a Lighthouse Report. If your site is feeling sluggish, check Why Is My Next.js Site Slow?.
Need a modern, fast, and accessible web application deployed to production? Explore my frontend development services or get in touch to discuss your next build.