Next.js supports several deployment modes — fully static export, server-side rendering with Node.js, or a hybrid. This guide covers deploying a Node.js-rendered Next.js app on your own VPS.
Prerequisites
- Node.js installed — see How to Install Node.js on Ubuntu & Debian (with NVM)
- Nginx installed
- Your Next.js application ready to deploy
Step 1 — Transfer and Build the Application
rsync -avz --exclude 'node_modules' --exclude '.next' ./myapp/ deploy@YOUR_SERVER_IP:/var/www/myapp/
cd /var/www/myapp
npm install
npm run build
Step 2 — Test the Production Server
npm run start
By default this runs on port 3000 — confirm it works, then stop it (Ctrl+C) to set up proper process management.
Step 3 — Run with PM2
pm2 start npm --name nextjs-app -- start
pm2 startup
pm2 save
Step 4 — Configure Nginx as a Reverse Proxy
server {
listen 80;
server_name myapp.example.com;
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_cache_bypass $http_upgrade;
}
}
Step 5 — Add HTTPS
sudo certbot --nginx -d myapp.example.com
Considering Static Export Instead (If Applicable)
If your Next.js app doesn't use server-side rendering features (API routes, dynamic SSR), a static export is simpler and more efficient to host:
next.config.js:
module.exports = {
output: 'export',
};
npm run build
This produces static HTML in the out directory, servable directly with Nginx as described in How to Host a Static Website on a VPS with Nginx — no Node.js runtime needed in production at all.
Caching Next.js's Static Assets
location /_next/static/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
Next.js's build output includes content-hashed filenames, making these safe to cache indefinitely — a new deployment automatically produces new filenames.
Deploying Updates
cd /var/www/myapp
git pull
npm install
npm run build
pm2 reload nextjs-app
Environment Variables
Next.js requires NEXT_PUBLIC_-prefixed variables to be available at build time for client-side use — ensure your .env.production file is correctly set before running npm run build. See How to Manage Environment Variables and Secrets on a VPS.
Common Errors
502 Bad Gateway — verify the Next.js process is actually running: pm2 status, and check logs with pm2 logs nextjs-app.
Environment variables not reflected in the client — client-visible variables must be set before npm run build, not just at runtime; rebuild after changing them.
Best Practices
- Use static export when SSR features aren't needed — simpler and more resource-efficient
- Cache the
_next/staticdirectory aggressively given its content-hashed filenames - Always rebuild after changing client-visible environment variables
Continue Reading
- How to Install Node.js on Ubuntu & Debian (with NVM)
- How to Deploy a Node.js Application with PM2 and Nginx
- How to Host a Static Website on a VPS with Nginx
Browse more articles in Static Site Hosting & Frontend Deployment.
