MENU
Self Hosting
Next.js does not need to run on a platform like Vercel. It can run as a long-lived Node.js process on any server or VM you control, started with the framework's own CLI. This trades away some of the automatic global infrastructure Vercel provides in exchange for full control over the environment -- useful when the app needs to live inside an existing data center, an internal network, or a specific compliance boundary.
Building and Starting
next build compiles the application; next start then boots a Node.js server that serves it, handling static assets, prerendered pages, on-demand ISR regeneration, Server Actions, and Route Handlers the same way Vercel's infrastructure would, just from a single process rather than a distributed edge network.
terminal:
npm run build # runs "next build"
npm start # runs "next start", listens on port 3000 by default
# override the port and hostname if needed
next start -p 4000 -H 0.0.0.0Because next start keeps a Node.js process running, it needs a process manager (pm2, systemd, or your container orchestrator's own restart policy) to keep it alive across crashes and server reboots -- unlike a serverless platform, nothing restarts it for you.
The output: 'standalone' Option
By default, next build assumes the final deployment will have access to the project's full node_modules folder, which for most apps is far larger than what's actually needed at runtime. Setting output: 'standalone' in next.config.js makes the build trace every file each page and Route Handler actually imports and copy only that minimal subset -- plus a small server.js entry point -- into .next/standalone. The result is a self-contained folder that can be deployed on its own, without running npm install on the target machine at all.
next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
}
module.exports = nextConfigterminal:
next build
cp -r public .next/standalone/
cp -r .next/static .next/standalone/.next/static
node .next/standalone/server.jsWhat You Lose Compared to Vercel
Middleware, Server Actions, ISR, and the Image Optimization endpoint all still work under next start -- none of them are Vercel-exclusive. What's missing is the infrastructure Vercel wraps around them:
- No distributed Edge Network. Middleware still runs, but as regular Node.js code on your one server or region, not replicated to edge locations near every visitor.
- No managed image CDN. The /_next/image optimization route still resizes and re-encodes images on request, but caches the results on local disk rather than a global CDN, so a slow origin server means slow first-load images until your own caching layer (or a CDN in front of it) takes over.
- No automatic preview deployments. Every branch/PR preview has to be wired up yourself, typically via CI building a separate container or environment per branch.
For production image handling, installing the optional sharp package is strongly recommended -- Next.js uses it for on-server image optimization and falls back to a much slower, unoptimized path without it.
terminal:
npm install sharpReverse-Proxying with nginx
In production, next start is rarely exposed to the internet directly. It's more common to put nginx (or another reverse proxy) in front, terminating TLS, serving .next/static assets straight off disk with long-lived cache headers, and forwarding everything else to the Node.js process.
nginx.conf:
server {
listen 80;
server_name example.com;
# hashed, immutable build assets -- safe to cache aggressively
location /_next/static/ {
alias /var/www/myapp/.next/static/;
expires 365d;
access_log off;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
}The most common way to package a self-hosted build like this for repeatable deployments is to wrap it in a container -- see Docker. If the app doesn't need server-side rendering at all, Static Export removes the Node.js server from the picture entirely.