Skip to content
NewHost
Menu

Next.js Standalone Output Explained - Setup, Folders and Deploys

Next.js standalone output explained - what output standalone copies, why public and static are missing, how to run server.js, monorepos and Docker.

By NewHost team · · 5 min read

Setting output: 'standalone' in next.config makes next build produce a .next/standalone folder containing a minimal server.js and only the node_modules files your app actually uses. You can copy that folder to a server and run node server.js without a full npm install. The catch that trips everyone up: it does not include your public folder or .next/static, so you must copy those in yourself. This guide explains what gets generated, the exact commands and when standalone is worth it.

How to enable it

Add one line to your config:

// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: "standalone",
};

export default nextConfig;

Then build as usual:

npm run build

What the build produces

After the build, you have:

.next/
  standalone/
    server.js          <- minimal Node.js server
    package.json
    node_modules/      <- only the traced files your app needs
    .next/
      server/          <- compiled server code
  static/              <- client JS, CSS and media (NOT inside standalone)
public/                <- your public files (NOT inside standalone)

Next.js uses output file tracing to follow every import and require from your server code and copies only those files into standalone/node_modules. A project whose full node_modules is very large typically ends up with a far smaller standalone folder, because development tools, build tools and unused packages are left out.

Why public and .next/static are missing

The Next.js team leaves these out on purpose, because many setups serve static files from a CDN instead of the Node.js server. If you want server.js to serve them (the normal case on a single server), copy them in after the build:

cp -r public .next/standalone/
cp -r .next/static .next/standalone/.next/

If you forget this step, pages render but look unstyled, client-side JavaScript fails to load (404s on /_next/static/...) and images from public are missing. That is the most common standalone bug by far.

A convenient approach is to put it in your build script:

{
  "scripts": {
    "build": "next build && cp -r public .next/standalone/ && cp -r .next/static .next/standalone/.next/",
    "start": "node .next/standalone/server.js"
  }
}

These commands assume a Linux or macOS shell, which is what build servers use. On Windows, run them in Git Bash or WSL, or use a small Node.js script with fs.cpSync.

Running server.js

Start the server with Node.js directly:

PORT=3000 HOSTNAME=0.0.0.0 node .next/standalone/server.js
  • PORT sets the port (default 3000).
  • HOSTNAME sets the address to bind to. Inside containers and on most platforms you want 0.0.0.0 so traffic from outside the process can reach it.

Do not use next start with standalone output. It prints a warning because standalone apps are meant to run through server.js.

Environment variables work as normal: server-side values are read from process.env at runtime, and NEXT_PUBLIC_ values were already inlined at build time. See Next.js environment variables in production for the details.

Image optimisation and sharp

Since Next.js 15, sharp is used automatically for image optimisation with standalone output, so you no longer need to install it manually. If you customised your image setup, check Next.js image optimisation when you self-host.

Standalone in a monorepo

In a monorepo (Turborepo, npm workspaces, pnpm workspaces), packages often live outside the app folder. Tell Next.js where the repository root is so tracing can include them:

// apps/web/next.config.js
const path = require("node:path");

module.exports = {
  output: "standalone",
  outputFileTracingRoot: path.join(__dirname, "../../"),
};

The standalone folder then mirrors your repository layout, so server.js ends up at .next/standalone/apps/web/server.js, and static files go to .next/standalone/apps/web/.next/static. Adjust your copy commands and start command to match.

When tracing misses a file

Tracing only sees files your code imports. Files loaded by path at runtime, such as a Prisma engine, a font file read with fs, or a JSON file loaded dynamically, can be missed. Add them explicitly:

module.exports = {
  output: "standalone",
  outputFileTracingIncludes: {
    "/api/report": ["./templates/**/*"],
  },
};

There is a matching outputFileTracingExcludes for files that get pulled in but are not needed. Both options are top-level config keys (they moved out of experimental in Next.js 15). The output docs list them in full.

A minimal Dockerfile

Standalone output is what makes small Next.js container images practical:

FROM node:24-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:24-alpine
WORKDIR /app
ENV NODE_ENV=production PORT=3000 HOSTNAME=0.0.0.0
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
COPY --from=build /app/public ./public
USER node
EXPOSE 3000
CMD ["node", "server.js"]

Should you use standalone?

Use standalone when Stick with next start when
You build Docker images and want them small Your host installs dependencies and runs npm start for you
You deploy by copying a build artefact to a server You deploy from Git and the build happens on the server
You want fast cold starts on container platforms You prefer the simplest possible setup

On managed Node.js hosting that builds from Git, both approaches work. On NewHost you set the start command yourself, so a standalone app uses node .next/standalone/server.js (with the copy step in your build script), while a regular app uses npm start.

Frequently asked questions

Why is my standalone Next.js app unstyled?

Because .next/static was not copied into .next/standalone/.next/static. The HTML loads but the CSS and JavaScript files return 404. Copy the folder after each build.

Does standalone output make my app faster?

Not at request time, because it is the same Next.js server. It makes deployments smaller and faster to copy and start, which matters most for containers.

Can I use standalone output with the App Router?

Yes. Standalone works with the App Router, Pages Router, Server Actions, ISR and image optimisation. It only changes how the build is packaged.

Where do I put my .env file with standalone output?

Preferably nowhere. Set environment variables in your hosting environment or container. NEXT_PUBLIC_ values must be present at build time, and server-side values must be present when server.js starts.

Want to deploy a standalone or standard Next.js build from Git to South African servers? See NewHost Next.js hosting, or deploy a Next.js app from GitHub step by step.

Related guides

Ready to launch on NewHost?

Choose a plan and go live today, or tell us what you need and we'll recommend the right setup.