Home/Learn/Next.js/Deploying — Vercel and Self-Hosting

Deploying — Vercel and Self-Hosting

Advanced
Production

Vercel runs Next as its authors intended and charges for it. Self-hosting is entirely viable and moves several framework features from automatic to your problem.

Overview

Next.js runs anywhere Node runs, but the framework assumes infrastructure — a CDN in front, a place to store the ISR cache, an image optimiser, a way to split routes into functions. On Vercel all of that is wired up and invisible. Self-hosting means providing it, which is well-documented and genuinely done at scale, but the pieces that "just worked" become things you own. Knowing which pieces those are is the difference between an informed choice and a surprise three weeks after migrating.

Vercel

What you get, and what it costs.

Zero-config, with per-request billing
// git push -> build -> deploy. Nothing to configure for the common case.
// Every branch gets a preview URL; production is instant to roll back
// because previous builds stay served.

// What is handled for you:
//   a global CDN for static assets and prerendered pages
//   each route as a serverless or edge function, scaled to zero
//   image optimisation on demand
//   the ISR cache, shared across instances
//   middleware at the edge

// The costs that surprise teams:
//   function invocations and duration — a dynamic route is billed per
//     request, so an accidental ○ -> ƒ regression shows up on the bill
//   image transformations — billed per source image
//   bandwidth
// A static-heavy content site is cheap here. A dynamic-heavy app with
// large traffic is where people start comparing.

// vercel.json for the things that are not automatic:
{
  "regions": ["bom1"],                       // put functions near the DB
  "crons": [{ "path": "/api/cron/digest", "schedule": "0 3 * * *" }]
}
// Region matters more than it sounds: functions in Washington talking
// to a database in Mumbai pay that round trip on every query.

Self-Hosting

Docker, and the four things you now own.

standalone in Docker; CDN, ISR cache, sharp are yours
# Dockerfile — multi-stage, using the standalone output
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.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                      # needs build-time env vars

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

// What becomes yours:
//   1. A CDN in front, or every asset is served by your Node process.
//   2. The ISR cache. With more than one instance, an in-memory cache
//      means instances disagree — configure a shared cache handler
//      (Redis) or accept the inconsistency.
//   3. Image optimisation. sharp must be installed, and it is CPU
//      work on your box; many teams point next/image at a CDN loader.
//   4. Zero-downtime deploys, health checks and log aggregation.

// NEXT_PUBLIC_ values are baked in at BUILD time, so one image cannot
// serve two environments with different public URLs. Build per
// environment, or make the value runtime-only and server-read.

Deploying Alongside a Separate Backend

Two deployables, and the ordering that avoids breaking a live page.

Backend first, same region, previews on staging
// This platform's shape: Next on Vercel, FastAPI on Fly, Postgres on
// Neon. Three deploy targets, two pipelines, one user-visible surface.

// Ordering, for the same reason as the Full-Stack track:
//   1. Deploy the BACKEND first, additively — the new API must still
//      serve the frontend bundle currently in people's browsers.
//   2. Then the frontend.
//   3. Remove old fields a release later.

// Keep them in the same region. Vercel in bom1 with Fly in sin means
// every server-rendered page pays a cross-region round trip.

// Env vars live in two places and drift. Keep .env.example current in
// both repos, and validate at boot so a missing value fails fast.

// Preview deployments must point at staging, never production — a
// preview build with the production DATABASE_URL is a real incident
// waiting for a careless migration.

// After a deploy, watch for five minutes: error rate, p95 latency,
// and one business metric. A green build that broke checkout is
// still a broken deploy.

Key Points to Remember

  • 1Vercel provides the CDN, function splitting, image optimisation and shared ISR cache that the framework assumes
  • 2Dynamic routes and image transforms are billed per use, so an accidental static-to-dynamic regression costs money
  • 3Self-hosting with output: standalone is viable but you own the CDN, the shared ISR cache, sharp and zero-downtime deploys
  • 4NEXT_PUBLIC_ values are baked in at build time, so one image cannot serve two environments
  • 5Deploy the backend first and additively, keep both in the same region, and point previews at staging

Interview Questions

Sign in to ask Aria
1

What does Vercel provide that you must build yourself when self-hosting?

Hard
2

Why can a single Docker image not serve two environments with different NEXT_PUBLIC_ values?

Hard
3

Why does the region of your functions matter?

Medium

Ask Aria about Deploying — Vercel and Self-Hosting

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…