Self-Hosting Next.js Without Vercel: What Works, What Breaks, What to Configure
Next.js runs anywhere Node.js does, and on a single server almost everything just works. The surprises: build-time environment variables, caching across instances, streaming behind a proxy, and a few Vercel-only conveniences. A practical guide to running Next.js on your own infrastructure.
Next.js is made by Vercel, and deploying to Vercel is the smoothest path. But it's an open-source framework, and it runs perfectly well on your own server, a container platform, or any host that runs Node.js. People move off Vercel for predictable pricing, long-running processes, keeping the app next to its database, or simply to have the choice.
On a single server, almost everything works out of the box. This guide covers the setup, and the handful of things that behave differently once Vercel's platform isn't doing them for you.
Checked against the Next.js 16 documentation in September 2026. The official self-hosting guide is the reference for your version.
The basic setup
A Next.js app runs as a Node.js server:
npm ci
npm run build # next build
npm start # next start — serves on $PORT (default 3000)
That's genuinely all it takes to run it. Put a reverse proxy in front (Nginx, Caddy, Traefik) to handle HTTPS and your domain, and you're live.
Standalone output for containers
For Docker, enable standalone output in next.config:
const nextConfig = { output: 'standalone' }
next build then produces .next/standalone/ — a minimal server (server.js) plus only the dependencies it needs, far smaller than a full node_modules. Two things to know:
- Copy the static files yourself. The standalone folder doesn't include
public/or.next/static/. Copy them in (to.next/standalone/publicand.next/standalone/.next/static), or serve them from a CDN. - Bind to all interfaces. Run it with
HOSTNAME=0.0.0.0so it accepts connections from outside the container, andPORTset to whatever your platform expects.
What just works
On a single Node.js server, these behave the same as on Vercel:
- Server-side rendering, React Server Components, and Server Actions
- API routes and route handlers
- Proxy (called middleware before Next.js 16)
- Static pages and incremental static regeneration (ISR)
- Image optimisation (
next/image), with no extra configuration undernext start - Streaming and Suspense
What behaves differently
1. NEXT_PUBLIC_ variables are fixed at build time
Variables prefixed with NEXT_PUBLIC_ are written into the JavaScript bundle during next build. Changing them in your host's settings afterwards does nothing until you rebuild. This bites people who build one Docker image and expect to configure it per environment.
Server-side variables (no prefix) are read at runtime and can change without a rebuild. Where a value needs to differ between environments and be visible in the browser, read it on the server and pass it down, rather than baking it in. (And remember: anything NEXT_PUBLIC_ is public. See How to Keep API Keys Out of an AI-Built App.)
2. Caching lives on the server's disk
Next.js caches rendered pages and fetched data. Self-hosted, that cache is stored on the local filesystem by default. On one server, that's fine. Two consequences:
- The cache must be writable and should persist. On a host with a temporary filesystem, the cache resets on every deploy — which is harmless but means more rendering.
- Multiple instances each have their own cache. Run three copies of your app and call
revalidatePathon one, and the other two keep serving old content. For multi-instance deployments, configure a shared cache with Next.js'scacheHandleroption (Redis is a common backing store).
3. Multiple instances need a few shared settings
Beyond the cache, if you run more than one instance behind a load balancer:
- Server Actions encryption key. Next.js encrypts data passed to Server Actions with a key generated fresh for each build. Build once and deploy that same build everywhere, or set
NEXT_SERVER_ACTIONS_ENCRYPTION_KEYwhen building so every build uses the same key. Otherwise one instance can't decrypt another's actions, and users see "Failed to find Server Action" errors. - Version skew. During a rolling deploy, a browser with the old version's JavaScript may talk to a server running the new one. Setting a
deploymentIdinnext.configlets Next.js detect this and reload cleanly.
On a single instance, none of this matters.
4. Streaming needs the proxy's cooperation
Streaming responses — Suspense boundaries, AI responses streamed token by token — work only if your reverse proxy passes chunks through as they arrive. Nginx buffers responses by default, which makes streaming arrive all at once at the end. Disable buffering for your app (for Nginx, the X-Accel-Buffering: no header or proxy_buffering off).
5. Image optimisation uses your CPU
next/image resizes images on request and caches the results. On Vercel, that's their compute. Self-hosted, it's your server's CPU and memory — a page full of large images can spike both on first load. Give the server headroom, keep the image cache persistent, or use an external image service.
6. Vercel-specific features need replacements
Some things in a Vercel-hosted app aren't Next.js features at all; they're Vercel platform products:
- Packages starting with
@vercel/— storage, analytics, edge config, and so on. - Cron jobs defined in
vercel.json— use your host's scheduler or a job library instead (Your App Needs Background Jobs). - Preview deployments per branch — a platform feature; see Preview Environments for Every Branch.
- The Edge runtime. Code marked to run on the Edge runtime still runs self-hosted — on your Node.js server, not at edge locations around the world.
Graceful shutdown and health checks
- Health checks. Add a route handler like
/api/healththat returns success only when the app can reach its database, and point your platform's health check at it. - Shutdown. On
SIGTERMorSIGINT, the Next.js server finishes in-flight requests before exiting. Give it time: the Next.js docs recommend a drain period of 10–30 seconds, so make sure your platform waits that long before force-killing the old instance.
Both are part of deploying without dropping requests — covered in Zero-Downtime Deploys for a Small App.
Where to host it
Anything that runs a long-lived Node.js process works: a VPS, a container platform, a PaaS that runs Docker images, or a managed development platform. The choice is mostly about how much operations work you want — VPS vs PaaS: Where Should a Small App Live? lays out the trade.
A single well-sized server is enough for a surprising amount of traffic, and it sidesteps every multi-instance issue above. Start there; add instances when you actually need them.
The checklist
-
next buildandnext startwork locally with production settings - Standalone output for containers, with
public/and.next/static/copied in - App listens on
$PORTand0.0.0.0 -
NEXT_PUBLIC_variables set at build time; secrets never prefixed - Cache directory writable (and shared, if running multiple instances)
- Same build across instances (or the same build-time encryption key), plus a
deploymentId - Proxy buffering off, so streaming works
-
@vercel/*packages andvercel.jsoncrons replaced - Health check route that tests the database
EasySpawn runs Next.js as a real Node.js server in a persistent workspace — so the cache and uploaded files survive restarts — with managed Postgres, automatic SSL, and your own domain, on flat monthly pricing. See how it works or join the waitlist.
Related: How to Deploy a v0 App · Why Does My App Work Locally but Not in Production? · What Is a Framework? · What Is Next.js? · Reverse Proxies Explained · Content Security Policy
Keep reading
Zero-Downtime Deploys for a Small App
You don't need Kubernetes to deploy without dropping requests. What actually causes downtime during a deploy — stopping before starting, no health checks, killed requests, and database changes the old code can't handle — and the four practices that fix each one.
Where Should User Uploads Go? Object Storage Explained
Profile photos that vanish after a deploy, a database bloated with images, a public bucket full of private documents. Where uploaded files should live, how object storage works, and the three decisions — public or private, who uploads, and how files are served — that keep uploads fast and safe.