Deploying — Vercel and Self-Hosting
AdvancedVercel 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.
// 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.
# 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.
// 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 AriaWhat does Vercel provide that you must build yourself when self-hosting?
Why can a single Docker image not serve two environments with different NEXT_PUBLIC_ values?
Why does the region of your functions matter?
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.