🚀 Deployment in Next.js: The Complete Guide

Shipping a Next.js application to production involves far more than running a single command. This tutorial walks through everything from preparing your codebase to choosing a hosting strategy, securing your app, and keeping it observable once it's live. Whether you're deploying to Vercel, a Docker container, or a Kubernetes cluster, you'll find a practical, production-ready path here.

Information

This guide assumes basic familiarity with npm or pnpm, the command line, and core Next.js concepts like the App Router.

📖 1. Introduction

Next.js supports multiple deployment models: fully managed platforms, self-hosted Node.js servers, containerized environments, and static exports. The right choice depends on your app's rendering strategy (SSR, SSG, ISR, or Edge), team expertise, and infrastructure constraints.

Deployment Models
Managed Platforms (Vercel, Netlify)
Self-Hosted (Node.js, Docker, Kubernetes)
Static Export (CDN-only)
Serverless / Edge Functions

Tip

If you're unsure where to start, Vercel's managed platform offers the smoothest path since it's built by the same team that maintains Next.js.

🧰 2. Preparing for Deployment

Before deploying, audit your project for production-readiness. This includes dependency hygiene, environment configuration, and verifying that your app builds cleanly.

  1. Ensure next, react, and react-dom versions are compatible and up to date.
  2. Remove unused dependencies and dev-only packages from production bundles.
  3. Confirm all environment variables are documented in .env.example.
  4. Run next lint and fix warnings that could indicate runtime issues.
  5. Test the app locally using a production build, not just next dev.

Warning

Never commit .env.local or any file containing secrets to version control. Use .gitignore to exclude them.

đŸ—ī¸ 3. Production Build

Next.js compiles your application into an optimized production bundle using the build command. This process performs code splitting, minification, static generation, and prerendering where possible.

Creating a production build

npm run build
# or
pnpm build
# or
yarn build

After building, start the optimized server locally to verify everything works as expected:

Starting the production server

npm run start

Note

The .next directory contains the compiled output. Do not edit it manually, and avoid committing it to version control.

✅ 4. Production Checklist

Use this checklist before pushing to production to catch common oversights.

CategoryCheckPriority
BuildProduction build completes with zero errorsCritical
EnvironmentAll required env vars set on the hostCritical
SecurityNo secrets exposed via NEXT_PUBLIC_ prefixCritical
PerformanceImages optimized via next/imageHigh
SEOMetadata and sitemap.xml configuredMedium
MonitoringError tracking and logging enabledHigh

▲ 5. Vercel Deployment

Vercel is the creator of Next.js and offers zero-configuration deployment with automatic CI/CD, edge caching, and preview URLs for every pull request.

Deploying via the Vercel CLI

npm i -g vercel
vercel login
vercel --prod

Best Practice

Use vercel (without --prod) to create a preview deployment before promoting to production.

đŸ–Ĩī¸ 6. Self-Hosting

Self-hosting gives you full control over infrastructure, at the cost of managing servers, scaling, and updates yourself. Next.js supports three self-hosting strategies:

Self-Hosting Strategies
Node.js Server (custom or standalone output)
Containerized
Static Export (no server required)
Docker
Kubernetes

Important

Self-hosted deployments lose access to some Vercel-specific optimizations like automatic ISR revalidation via the edge network unless configured manually.

đŸŸĸ 7. Node.js Deployment

The simplest self-hosted approach runs Next.js as a long-lived Node.js process behind a process manager.

Standard Node.js deployment

npm run build
npm run start -- -p 3000

For production resilience, use a process manager like pm2 to handle crashes, restarts, and clustering.

Running with PM2

npm i -g pm2
pm2 start npm --name "next-app" -- start
pm2 save
pm2 startup

Tip

Enable output: "standalone" in next.config.js to produce a minimal, self-contained build with only the necessary files and a small server bundle.

đŸŗ 8. Docker Deployment

Containerizing your Next.js app ensures consistent environments across development, staging, and production.

Multi-stage Dockerfile

FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]

Build and run the container

docker build -t next-app .
docker run -p 3000:3000 next-app

Best Practice

Always use the output: "standalone" setting with Docker to keep image sizes small by excluding unnecessary dependencies.

â˜¸ī¸ 9. Kubernetes Deployment

For applications requiring horizontal scaling, self-healing, and rolling updates, Kubernetes orchestrates your containerized Next.js app across a cluster of nodes.

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: next-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: next-app
  template:
    metadata:
      labels:
        app: next-app
    spec:
      containers:
        - name: next-app
          image: your-registry/next-app:latest
          ports:
            - containerPort: 3000
          env:
            - name: NODE_ENV
              value: "production"
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: next-app-service
spec:
  selector:
    app: next-app
  ports:
    - port: 80
      targetPort: 3000
  type: LoadBalancer

Note

Configure a readinessProbe and livenessProbe so Kubernetes can detect and restart unhealthy pods automatically.

đŸ“Ļ 10. Static Export

If your app has no server-side requirements (no API routes, no dynamic SSR), you can export it as fully static HTML, deployable to any static host or CDN.

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: "export",
};

module.exports = nextConfig;

Generating the static export

npm run build
# Output is generated in the "out" directory

Caution

Static export does not support getServerSideProps, API routes, middleware, or ISR. Plan your rendering strategy accordingly.

🌐 11. Edge Deployment

Edge runtimes execute code close to the user, reducing latency for personalization, authentication checks, and lightweight rendering logic.

Enabling the Edge runtime in a route

export const runtime = "edge";

export async function GET(request) {
  return new Response("Hello from the edge!");
}

Information

The Edge runtime has a smaller API surface than Node.js — it doesn't support native Node.js modules like fs or net.

⚡ 12. Serverless Deployment

Serverless functions scale automatically and charge per invocation, making them cost-effective for variable traffic patterns. Platforms like Vercel, AWS Lambda, and Netlify Functions all support this model natively for Next.js.

ModelCold StartsBest For
Serverless (Node.js)ModerateFull Node.js API access, SSR pages
Edge FunctionsMinimalLow-latency, lightweight logic
Long-Running ServerNonePredictable, high-throughput traffic

🔑 13. Environment Variables

Next.js loads environment variables from .env files at build and runtime. Variables prefixed with NEXT_PUBLIC_ are exposed to the browser; all others remain server-only.

.env.production

DATABASE_URL=postgres://user:pass@host:5432/db
NEXT_PUBLIC_API_URL=https://api.example.com
SESSION_SECRET=your-secret-here

Danger

Never prefix sensitive values like API keys or database credentials with NEXT_PUBLIC_— doing so bundles them into client-side JavaScript, exposing them to anyone.

🌍 14. Domains

Once deployed, point a custom domain at your hosting provider by updating DNS records.

  • Add an A record pointing to your host's IP, or a CNAME for platforms like Vercel.
  • Configure both the apex domain (example.com) and www subdomain.
  • Set up a redirect so one variant (usually www) canonically redirects to the other.

Tip

DNS propagation can take up to 48 hours, though it usually completes within minutes on most modern registrars.

🔒 15. HTTPS & SSL

Serving your app over HTTPS is non-negotiable for production. Most managed platforms provision SSL certificates automatically via Let's Encrypt.

For self-hosted deployments, tools like certbot automate certificate issuance and renewal:

Provisioning a certificate with Certbot

sudo certbot --nginx -d example.com -d www.example.com

Important

Redirect all http:// traffic to https:// and enable HSTS headers to prevent downgrade attacks.

đŸŒŠī¸ 16. CDN Integration

A CDN caches static assets and, in some setups, full pages, at edge locations worldwide, reducing latency and origin load.

Request Flow
User Request
Nearest CDN Edge
Origin Server (Next.js app)
Cache Hit → Served instantly
Cache Miss → Forwarded to origin

Tip

Set appropriate Cache-Control headers on static assets and use ISR for pages that update periodically without a full rebuild.

🔀 17. Reverse Proxy

A reverse proxy sits in front of your Next.js server, handling SSL termination, load balancing, and routing to multiple backend instances.

Internet Traffic
Reverse Proxy (Nginx / Caddy)
Next.js Instance 1
Next.js Instance 2
Next.js Instance 3

âš™ī¸ 18. Nginx Configuration

A minimal Nginx configuration proxies incoming requests to your Node.js process running on a local port.

/etc/nginx/sites-available/next-app

server {
  listen 80;
  server_name example.com www.example.com;

  location / {
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }
}

Note

The Upgrade and Connection headers are required to support WebSocket connections used by Next.js's hot module reloading and certain real-time features.

đŸŽī¸ 19. Performance Optimization

Production performance depends on how well you leverage Next.js's built-in optimization features.

  • Use next/image for automatic image resizing, lazy loading, and modern format conversion.
  • Use next/font to self-host fonts and eliminate layout shift.
  • Enable ISR for pages with semi-static content to avoid full rebuilds.
  • Analyze bundle size with @next/bundle-analyzer to catch bloat early.
  • Leverage React.lazy and dynamic imports for code splitting on heavy components.

Tip

Run next buildand review the printed route summary — it shows which pages are static, server-rendered, or edge-rendered.

đŸ›Ąī¸ 20. Security Best Practices

AreaRecommendation
HeadersSet Content-Security-Policy, X-Frame-Options, and Referrer-Policy
DependenciesRun npm audit regularly and patch known vulnerabilities
SecretsStore secrets in a vault or platform-managed environment variables
Input ValidationValidate and sanitize all data in API routes and Server Actions
Rate LimitingProtect public APIs and forms from abuse

Important

Keep Next.js itself updated — security patches are released regularly, and outdated versions can carry known vulnerabilities.

📊 21. Monitoring

Monitoring gives you visibility into your app's health: response times, error rates, and resource usage.

Built into Vercel deployments, tracking Core Web Vitals and real-user performance metrics automatically with zero configuration.

An error-tracking platform that captures exceptions, stack traces, and performance traces across both client and server code.

A full-stack observability platform combining metrics, logs, and traces, well-suited for larger self-hosted infrastructures.

📝 22. Logging

Structured logs make debugging production issues far easier than scattered console.log calls.

Structured logging example

console.log(JSON.stringify({
  level: "info",
  message: "User logged in",
  userId: user.id,
  timestamp: new Date().toISOString(),
}));

Tip

Forward logs to a centralized service (like Datadog, Logtail, or CloudWatch) so they persist beyond a single server's lifecycle, which is essential in serverless and container environments.

📈 23. Analytics

Analytics track user behavior and business metrics, distinct from performance monitoring. Popular options include Vercel Analytics, Google Analytics, and Plausible.

Example

A typical setup tracks page views, conversion events, and Core Web Vitals together to correlate performance with user engagement.

🔄 24. CI/CD Pipelines

A CI/CD pipeline automates testing, building, and deploying your app whenever code changes.

🐙 25. GitHub Actions

GitHub Actions can automate builds and deployments directly from your repository.

.github/workflows/deploy.yml

name: Deploy Next.js App

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Build application
        run: npm run build

      - name: Deploy
        run: npx vercel --prod --token=${{ secrets.VERCEL_TOKEN }}

Best Practice

Store sensitive tokens as encrypted GitHub Secrets rather than hardcoding them into workflow files.

đŸˇī¸ 26. Versioning

Tag each production release to maintain a clear history and enable quick rollbacks.

Tagging a release

git tag -a v1.4.0 -m "Release 1.4.0: add checkout flow"
git push origin v1.4.0

Tip

Follow Semantic Versioning (MAJOR.MINOR.PATCH) so consumers of your releases can gauge the impact of an update at a glance.

â†Šī¸ 27. Rollbacks

Even with careful testing, production issues happen. A fast rollback strategy minimizes downtime.

  1. On managed platforms like Vercel, use the dashboard to instantly promote a previous deployment to production.
  2. On self-hosted setups, keep the previous Docker image tagged and ready to redeploy.
  3. In Kubernetes, run kubectl rollout undo deployment/next-app to revert to the prior revision.

Warning

Always investigate whya rollback was needed before redeploying the fix — rolling back only buys time, it doesn't resolve the root cause.

🐛 28. Common Deployment Issues

IssueLikely CauseFix
Blank page after deployMissing environment variablesVerify all required vars are set on the host
500 errors on API routesUnhandled exceptions or DB connection issuesCheck server logs and connection strings
Stale contentAggressive CDN cachingAdjust Cache-Control or trigger revalidation
Large bundle sizeUnoptimized importsUse dynamic imports and analyze the bundle
Build fails in CI, works locallyNode version mismatchPin the Node.js version in CI config

❓ 29. Frequently Asked Questions

Question

Can I deploy a Next.js app with API routes as a static export?

Answer

No. Static export (output: "export") disables API routes, middleware, and server-side rendering entirely, since there's no server to run them.

Question

Do I need a reverse proxy if I'm using Vercel?

Answer

No. Vercel manages routing, SSL termination, and load balancing for you automatically. Reverse proxies like Nginx are typically only needed for self-hosted deployments.

Question

How do I handle database migrations during deployment?

Answer

Run migrations as a separate step in your CI/CD pipeline before traffic is routed to the new deployment, to avoid schema mismatches during the rollout.

📌 30. Summary

Deploying a Next.js application successfully means matching your rendering strategy to the right hosting model, securing the app with HTTPS and proper headers, automating releases through CI/CD, and maintaining visibility through monitoring and logging once live.

Summary

  • Choose a hosting model that fits your rendering needs: managed, self-hosted, static, or serverless.
  • Always build and test a production bundle before deploying.
  • Secure environment variables, enforce HTTPS, and set protective headers.
  • Automate deployments with CI/CD and keep a fast rollback path ready.
  • Monitor, log, and analyze your app continuously after launch.
>>"Deployment isn't the finish line — it's the starting point of your application's real life."