How to deploy a Next.js app
A Next.js app can be deployed four ways: as a Node.js server with next build and next start, as a Docker container, as a static export served as plain files, or through a platform adapter that runs it for you. The first two support every Next.js feature. A static export does not support anything that needs a server, such as ISR, server actions or Proxy.
Checked against current documentation on 30 September 2026.
The four options
“Next.js can be deployed as a Node.js server, Docker container, static export, or adapted to run on different platforms.”
| Option | Features supported | You look after |
|---|---|---|
| Node.js server with next start | All | The server, process manager, TLS and updates |
| Docker container | All | The container host, TLS and updates |
| Static export | Limited: nothing that needs a server | Only file hosting |
| Adapter or platform | Varies by platform | Depends on the platform |
Features that need a server include Incremental Static Regeneration, server actions, Proxy (what was called middleware), Draft Mode, cookies and route handlers that read the request. Image optimisation with the default loader needs a server too. If your app uses any of them, which most App Router apps do, a static export is out.
A quick way to decide: does anything in the app need to run when a person asks for a page? If yes, you need a server. If everything can be worked out at build time, a static export will do. The guide to self-hosting covers what a server needs.
As a Node.js server
Any provider that runs Node.js can host Next.js. Your package.json needs the build and start scripts that create-next-app writes for you. Then:
- 1BuildRun npm run build on the server or in CI. This produces the .next directory.
- 2StartRun npm run start, which runs next start on port 3000 by default. Set PORT to change it.
- 3Keep it runningUse a process manager such as systemd or pm2 so it restarts after a crash or a reboot.
- 4Put a proxy in frontThe Next.js docs recommend a reverse proxy such as nginx rather than exposing the server directly. It can handle malformed requests, slow connections, payload limits and rate limiting. Turn buffering off, or streamed responses arrive all at once.
- 5Add TLSLet the proxy terminate HTTPS. Caddy does this automatically; with nginx you would add a certificate tool.
[Unit] Description=Next.js app After=network.target [Service] WorkingDirectory=/srv/app ExecStart=/usr/bin/npm run start Environment=NODE_ENV=production PORT=3000 Restart=always KillSignal=SIGTERM TimeoutStopSec=30 [Install] WantedBy=multi-user.target
This supports every feature. ISR and image optimisation work with no configuration on a single server with a persistent disk, because the cache lives on that disk. Running more than one copy is different, and the self-hosting guide covers it.
Environment variables have a catch. Anything prefixed NEXT_PUBLIC_ is written into the JavaScript bundle at build time, so changing it later needs a rebuild. Other variables are read on the server at run time, but only in code that renders dynamically.
As a Docker container
Docker works anywhere a container runs: a VPS, Kubernetes, a cloud provider or a platform that accepts images. The Next.js docs point to three official examples, including one that uses standalone output to produce a minimal image with only the files it needs.
// next.config.ts
const nextConfig = { output: 'standalone' }
export default nextConfigCopy .next/standalone, .next/static and public into a small Node image and run node server.js. The full build, with a multi-stage Dockerfile, is in how to dockerize a Next.js app. Two things catch people out. The ISR cache lives inside the container, so it starts empty after every deploy unless you mount a volume. And if you run more than one copy, each keeps its own cache unless you configure a shared one.
Because server-side variables are read at run time, one image can be promoted from staging to production with different values. That only holds for variables read in dynamic code. If you want a container host that also offers a database, compare Docker hosting providers before you commit.
As a static export
Set output to export and next build writes plain HTML, CSS and JavaScript to the out directory. Any web server that serves static files can host it: Nginx, Apache, AWS S3 or GitHub Pages. It is the cheapest option and the right one for a site with no server-side behaviour.
- Not supported: ISR, server actions, Proxy, cookies, rewrites, redirects, custom headers, Draft Mode and intercepting routes.
- Dynamic routes must list every page with generateStaticParams, and cannot set dynamicParams to true.
- Route handlers only work for GET, and must be marked static with export const dynamic = force-static.
- next/image needs a custom loader, because the default one optimises at request time.
- Redirects and headers move to your web server. In Nginx, dynamic routes need a rewrite to the .html file when trailingSlash is false.
Next.js reports an error if you use one of these in next dev with a static export, which is better than finding out after deploy. If your needs grow later, the docs say you can start static and add server features when you need them.
On a platform
You connect a Git repository and the platform builds each commit and runs it. This is the least work and where most people start. The Next.js docs split platforms into two groups. Verified adapters are open source, run the Next.js compatibility test suite and live under the Next.js GitHub organisation. Today those are Vercel and Bun. Other platforms, including Cloudflare, Netlify, AWS Amplify and Firebase App Hosting, offer their own integrations. The docs say those are not verified, so feature support may vary.
- Vercel is a verified adapter. Pro is $20 per developer seat per month, with a usage credit and pay-as-you-go beyond it, as of the date above.
- Railway, Render, DigitalOcean, Fly.io and Google Cloud Run all have deploy templates in the Next.js docs. They run your app as a Node server or a container.
- Helm7 runs the app as a container alongside its Postgres, auth, storage, jobs and domains on one bill, from $12 a month. It is newer than the others and only runs in the EU, in Falkenstein and Helsinki. See the platform overview and pricing.
When you compare, ask four things. Where does the code run? What happens to a slow request? Where does the database live? What is the bill when traffic spikes? How to host a Next.js app goes through each with numbers, and Helm7 has side-by-side comparisons with other platforms.
Edge cases that catch people out
- Port. next start listens on 3000. If your host expects another port, set the PORT variable rather than editing scripts.
- Build machine. Building on a small server can run it out of memory. Build in CI or a container and ship the result.
- Trailing slashes. A static export writes /blog/post-1.html by default, so a plain file host may need a rewrite to find it. Setting trailingSlash to true writes /blog/post-1/index.html instead.
- Old browser tabs. After a deploy, someone with the old page open may ask for files that no longer exist. Set deploymentId if you run rolling deploys.
- Docker on a Mac or Windows laptop. The Next.js docs suggest running npm run dev locally instead of in Docker, for speed.
Which to choose
- A marketing site or blog with no server features: a static export.
- An app, and you would rather not run servers: a platform.
- An app that also needs a database, auth and files, and you want one bill: a platform that hosts both, or a container host plus separate backend services.
- An app where you want full control of the machine: Docker or a Node server on a server you run.
Whatever you pick, check three things before you go live: the app answers on the production URL, streamed pages arrive in pieces rather than all at once, and a redeploy does not lose anything a user was waiting for. The quickstart shows a full deploy on Helm7.
Common questions
Can I deploy Next.js without Vercel?
Yes. Next.js runs anywhere Node.js does, and the Next.js documentation lists Node servers, Docker containers, static exports and platform adapters as supported ways to deploy it. Node and Docker deployments support all features.
Does ISR work when I host Next.js myself?
Yes, with no configuration on a single server that keeps its disk. Running several copies needs a shared cache handler so they agree on what has been revalidated.
What is output standalone?
A next.config setting that makes next build copy only the files needed to run the app into .next/standalone, with a server.js to start it. It is the usual basis for a small Docker image.
Can I use a static export if I use the App Router?
Yes, if you avoid features that need a server. Server Components run at build time and are fine. Server actions, ISR, Proxy, cookies and default image optimisation are not supported in a static export.
Do environment variables work the same on every option?
Variables prefixed NEXT_PUBLIC_ are written into the JavaScript at build time on every option. Other variables are read on the server at run time in code that renders dynamically, which a static export has no server to do.