Learning objectives
After reading this article you will be able to:
- Choose between a Node.js server, standalone output and a static export
- Build and start the project with the right port and environment variables
- Verify the deploy and fix the most common errors
On this page
Running npm run dev on your machine is only the start. For other people to reach the site, Next.js has to be built for production and kept on a server that stays on, with the right port, variables and Node version.
Next.js does not depend on any specific platform. The official documentation describes three ways to host it: a Node.js server, a Docker image, or static HTML files. Which one fits depends on the server features your project uses.
Which hosting mode should you choose?#
| Mode | Config and command | Needs Node.js in production? | When to use |
|---|---|---|---|
| Node.js server | next build + next start |
Yes | Full app, every feature |
| Standalone | output: 'standalone' + node server.js |
Yes, without node_modules |
Smaller deploy, Docker, containers |
| Static export | output: 'export' |
No | Site with no server features |
Pick the static export only if the site works with no code running on the server. The documentation lists what is not supported in that mode: Server Actions, cookies, rewrites, redirects and headers in next.config, proxy (formerly middleware), ISR, Draft Mode, dynamic routes without generateStaticParams() and the default image optimizer. If you use any of them, stay with the Node.js server. For the static format in general, see what a static site is.
What do you need before you start?#
- A recent Node.js version. The Next.js documentation lists the minimum it requires. In production, use the current Active LTS of Node.js; the official release schedule shows which one that is.
- Scripts in
package.json, whichcreate-next-appalready generates:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}- A committed lockfile (
package-lock.json,pnpm-lock.yaml) so every machine installs the same versions. - A place to run it: a VPS, a container or a hosting platform. The difference is covered in VPS vs cloud platform.
How do you host it as a Node.js server?#
This is the path that supports every feature. On the server (or in CI), run:
npm ci
npm run build
npm run startnext build creates the .next folder and prints a route table, where ○ is static and ƒ is rendered on demand. next start runs the production server on 0.0.0.0, port 3000 by default. To change the port, use the PORT variable or the -p flag:
PORT=8080 npm run start
npx next start -p 8080PORT must be in the process environment. Putting it in .env does not work, because the HTTP server starts before Next.js loads that file.
With next start, image optimization through next/image works with zero configuration. On glibc-based Linux, the documentation warns that it may need a memory allocator tweak to avoid excessive RAM use.
How do you build standalone or a static export?#
Standalone, for a smaller deploy#
Standalone mode copies only the files the server actually uses, including the needed parts of node_modules. Enable it in next.config.ts:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
};
export default nextConfig;After next build, the .next/standalone folder contains a minimal server.js. It does not copy public or .next/static by default. Copy them yourself:
npm run build
cp -r public .next/standalone/
cp -r .next/static .next/standalone/.next/
node .next/standalone/server.jsserver.js reads PORT and HOSTNAME:
PORT=8080 HOSTNAME=0.0.0.0 node .next/standalone/server.jsIn monorepos, file tracing starts at the project folder. If files outside it are missing, set outputFileTracingRoot in next.config. To package everything in an image, see how to put an app in Docker.
Static export, for sites with no server-side code#
If the site is only content, change the config:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "export",
};
export default nextConfig;next build now creates the out folder with one HTML file per route, plus CSS and JS. Any static file server can serve it. If you use next/image, define a custom loader in images, since the default optimizer needs a server.
How do you set environment variables?#
By default, variables are available only on the server. Those starting with NEXT_PUBLIC_ are inlined into the JavaScript during next build: changing the value later means building again. Variables read on the server during dynamic rendering (for example, after await connection()) are evaluated at run time, so one build can serve several environments.
Never put secrets in NEXT_PUBLIC_ variables, because they ship to the browser. The general pattern is in what environment variables are.
How do you check that it worked?#
- Logs:
next startprints the address and port, with no errors after it. - Request: open the home page and a dynamic route on the public address.
- Assets: in the browser, confirm the files under
/_next/static/load with status 200. - Restart: restart the process and check that the site comes back on its own. The Next.js server finishes in-flight requests when it receives
SIGTERMorSIGINT.
If a reverse proxy such as nginx sits in front, disable buffering so streaming works (for example, with the X-Accel-Buffering: no header).
What are the most common errors?#
- Site opens locally but not on the public address: check the host and port the process listens on.
next startalready listens on0.0.0.0by default, but the standaloneserver.jsbinds to the address in theHOSTNAMEvariable. SetHOSTNAME=0.0.0.0andPORTin the start command. - Page without CSS or broken images in standalone: you forgot to copy
publicand.next/static. Failed to find Server Action: with several instances, each build generates its own encryption key. Set the sameNEXT_SERVER_ACTIONS_ENCRYPTION_KEYfor all of them at build time.- A
NEXT_PUBLIC_variable with an old value: it was inlined in the build. Rebuild. - Process killed during
next build: usually out of memory. Give it more RAM or build in CI instead. - Stale content with more than one instance: the page cache lives on each instance's disk. To share it, configure a cache handler, as the documentation describes.
How to do this on Square Cloud#
On Square Cloud, deploy is self-service: you upload the project and control the configuration. Node.js is one of several runtimes, and the static sites runtime is an option for the export's out folder: on it, nginx is always online serving the files, with none of your code running on the server. You can deploy by ZIP upload in the dashboard, the CLI, GitHub (a push deploys) or the VS Code extension.
The platform has no build step. Run next build in an external CI such as GitHub Actions and upload the result, or put the build in the start command: npm run build && npm start. In that case, everything the build needs must be in dependencies, because devDependencies are not installed. The server must listen on 0.0.0.0, on the port in the PORT variable, which next start already reads.
The squarecloud.app file (name, main file, memory and version) is optional: the dashboard generates it on deploy, or you can write it at the project root. Environment variables are set per application, in the dashboard, API, CLI or VS Code. The dashboard imports a .env, and a change applies on the next restart, except for NEXT_PUBLIC_ variables, which only change with a new next build.
The application runs in an always-on container. Automatic restart comes on when you deploy from the dashboard and only kicks in when the process exits with an error. The plan's RAM is a pool shared across your applications, with a 512 MB minimum per web application.
Every web application gets a *.squareweb.app subdomain with HTTPS, and a custom domain is available from the Standard plan (see how to use a custom domain). Plans are paid, start at R$12.49 per month and all include cookie-free web analytics. The details are on the sites page.
Website hosting
Static and SSR sites with automatic TLS and a global CDN
FAQs
Which Node.js version does Next.js require?
The installation page of the Next.js documentation lists the minimum Node.js version. In production, use the current Active LTS of Node.js and the same version on your computer and on the server.
Can I host Next.js as a static site?
Yes. With output: 'export', next build generates an out folder with HTML, CSS and JS. Server Actions, cookies, redirects and rewrites in next.config, proxy (formerly middleware) and ISR do not work in that mode.
Do I need to run next build on the server?
Not necessarily. You can build on your computer or in CI and ship the result. With output: 'standalone', the .next/standalone folder holds only the files needed, with no node_modules install.
How do I change the Next.js port in production?
Use the PORT variable or the -p flag of next start. The default is 3000. PORT does not work inside a .env file, because the HTTP server starts before .env is read.
Why does my Next.js app work locally and break on the server?
The usual causes are a different Node version, environment variables missing at build or run time, a server listening only on localhost, and running out of memory during next build.
More in Websites
See all 20 articles- What is a static site (and how to host one)A static site is a set of ready-made HTML, CSS and JavaScript files served the same to every visitor. Learn how it works, when to use one and how to host it.
- How much does it cost to host a website?Hosting a website costs anywhere from nothing to a few dozen dollars a month. See what goes into the bill: hosting, domain, traffic and extras, with real limits.
- How much does static site hosting cost?Hosting a static site costs between zero and a few dozen dollars a month in most cases. See how traffic sets the price, with step-by-step math.
- How much does it cost to host a Next.js app?Hosting a Next.js app costs from zero with a static export to tens of dollars a month with a server. See the billing models, traffic math and hidden costs.