Technology · Next.js

Next.js Deployment

Deploy Next.js apps to production on Vercel, Docker, and other platforms.

TL;DR
  1. 01Run npm run build to compile your app for production.
  2. 02Deploy to Vercel with one command or by connecting a Git repo.
  3. 03Set environment variables in your deployment platform dashboard.

Building for Production

  • Build your app for production.
    npm run build
    npm start
  • Build creates .next folder with optimized files.
  • Test production build locally before deploying.
    npm run build
    npm start
    # Visit http://localhost:3000
  • Inspect the build output for page sizes and bundle weights.
    npm run build
    # Route           Size   First Load JS
    # /               5 kB         87 kB
    # /blog/[slug]    3 kB         85 kB
  • Use output: 'standalone' to create a minimal deployment folder.
    // next.config.js
    module.exports = {
      output: "standalone"
      // .next/standalone contains everything needed to run
    };
  • Set NODE_ENV=production when running the server manually.
    NODE_ENV=production node .next/standalone/server.js

Vercel Deployment

  • Deploy to Vercel (easiest option).
    npm install -g vercel
    vercel
  • Connect Git repository for automatic deployments.
    git push  # Automatically deploys to Vercel
  • Vercel is created by Next.js team.
  • Preview deployments are created automatically for every pull request.
  • Set environment variables using the Vercel CLI.
    vercel env add DATABASE_URL production
    vercel env add NEXT_PUBLIC_API_URL production
  • Override the build command in vercel.json if needed.
    {
      "buildCommand": "npm run build",
      "outputDirectory": ".next"
    }

Docker Deployment

  • Create Dockerfile for Docker deployment.
    FROM node:18-alpine
    
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci
    
    COPY . .
    RUN npm run build
    
    EXPOSE 3000
    CMD ["npm", "start"]
  • Build and run Docker image.
    docker build -t my-app .
    docker run -p 3000:3000 my-app
  • Use multi-stage builds to reduce the final image size.
    FROM node:18-alpine AS builder
    WORKDIR /app
    COPY . .
    RUN npm ci && npm run build
    
    FROM node:18-alpine AS runner
    COPY --from=builder /app/.next/standalone ./
    CMD ["node", "server.js"]
  • Pass environment variables at container runtime.
    docker run -p 3000:3000 -e DATABASE_URL=postgres://... my-app
  • Use docker-compose for local development with a database.
    services:
      app:
        build: .
        ports: ["3000:3000"]
      db:
        image: postgres:15
        environment:
          POSTGRES_PASSWORD: secret

Environment Variables

  • Set environment variables in deployment platform.
    # Vercel dashboard
    vercel env add DATABASE_URL
    vercel env add NEXT_PUBLIC_API_URL
  • Use .env.production for local production testing.
    # .env.production
    DATABASE_URL=postgresql://prod-db
    NEXT_PUBLIC_API_URL=https://api.prod.com
  • Prefix public variables with NEXT_PUBLIC_ to expose to the browser.
    NEXT_PUBLIC_STRIPE_KEY=pk_live_abc123
    DATABASE_URL=postgres://secret  # server-only
  • Validate required env variables at startup to catch missing config early.
    // lib/env.ts
    if (!process.env.DATABASE_URL) {
      throw new Error("DATABASE_URL is required");
    }
  • Store secrets in your CI/CD platform and never commit them to Git.
    # GitHub Actions
    env:
      DATABASE_URL: ${{ secrets.DATABASE_URL }}

Performance Optimization

  • Enable Image Optimization for faster images.
    import Image from 'next/image';
    
    <Image
      src="/photo.jpg"
      alt="Photo"
      width={800}
      height={600}
      priority
    />
  • Use static exports for fully static sites with no server needed.
    // next.config.js
    module.exports = {
      output: "export"
      // Creates an out/ folder you can host on any CDN
    };
  • Enable compression for smaller HTTP responses.
    module.exports = {
      compress: true // enabled by default in production
    };
  • Configure CDN caching for static assets.
    module.exports = {
      headers: async () => [
        {
          source: "/_next/static/(.*)",
          headers: [{ key: "Cache-Control", value: "public, max-age=31536000, immutable" }]
        }
      ]
    };
  • Run lighthouse audits against the deployed production URL.
    npx lighthouse https://your-app.vercel.app --output html

Tip: Use Vercel for simplest deployment — it's optimized for Next.js and includes preview deployments.

Warning: Never commit .env.production files — use your deployment platform's secret management.

Next.js Database IntegrationNext.js Directives