Topic 13 / 13

Deploying Next.js to Production

~10 min read  //  Next.js Series  //  Coding India

Environment Variables

# .env.local (git-ignored)
DATABASE_URL=postgres://...
AUTH_SECRET=...
NEXT_PUBLIC_SITE_URL=https://codingindia.in

Two scopes, one rule: plain names are server-only; anything prefixed NEXT_PUBLIC_ is inlined into the browser bundle — never put secrets there.

The Production Build

npm run build
npm start            # serves the optimised build

The build output table is your map — each route marked static (○), SSG (●), or dynamic (ƒ), with bundle sizes. Check it before every deploy; an unexpectedly dynamic route usually means an accidental cookies() or no-store somewhere.

Option 1: Vercel

The zero-config path from the creators of Next:

  1. Push the repo to GitHub.
  2. Import it at vercel.com — build settings auto-detected.
  3. Add env vars in the dashboard.

You get: deploys on every push, preview URLs per pull request, CDN, automatic HTTPS, and serverless scaling of dynamic routes. For most products this is the right default.

Option 2: Self-Hosting with Docker

Full control on your own VPS. Enable standalone output for a minimal image:

// next.config.mjs
export default { output: "standalone" };
# Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
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"]
docker build -t ci-site .
docker run -d -p 3000:3000 --env-file .env.production ci-site

Nginx in front for TLS and caching — the same reverse-proxy pattern as the Django deployment topic:

server {
  listen 80;
  server_name codingindia.in;

  location /_next/static/ {
    proxy_pass http://127.0.0.1:3000;
    add_header Cache-Control "public, max-age=31536000, immutable";
  }
  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

Then certbot --nginx for HTTPS, and run migrations (npx prisma migrate deploy) in CI before swapping containers.

Launch Checklist

  • Env vars set per environment; no secrets in NEXT_PUBLIC_.
  • Build output reviewed — routes static where expected, bundles sane.
  • metadataBase, sitemap, robots, OG images verified.
  • Auth flows tested against production URLs (OAuth callback URLs updated!).
  • Error monitoring (Sentry) and analytics wired.
  • Database backed up and pooled; migrate deploy in the pipeline.

Series Wrap

You can now build and ship a complete product on Next.js: file-based routing with streaming layouts, server components reading a typed database, mutations via server actions, auth, SEO, image optimisation, and two deployment paths. Combine it with the React series (the component model underneath) and the CSS series (the design layer) — then go build the thing you’ve been putting off.