# Next.js Output Standalone Configuration: Implications for Custom Server Setups

> Explore Next.js output standalone configuration implications for custom servers. Learn how it creates a self-contained runtime and impacts server setups.

- Repository: [Vercel/next.js](https://github.com/vercel/next.js)
- Tags: deep-dive
- Published: 2026-02-16

---

**When you enable `output: 'standalone'` in Next.js, the framework generates a self-contained runtime in `.next/standalone` that requires launching via `node .next/standalone/server.js` instead of `next start`, serializes configuration into the `__NEXT_PRIVATE_STANDALONE_CONFIG` environment variable, and restricts bundler flags while maintaining compatibility with custom server wrappers.**

The `nextjs output standalone configuration` fundamentally changes how Next.js applications are deployed, particularly when you use a custom server setup. In the standard Vercel/next.js repository, this mode creates a minimal, production-ready bundle by tracing only the files actually required at runtime. Understanding these implications ensures your custom server integration remains functional while leveraging the benefits of reduced deployment artifacts.

## How `output: 'standalone'` Changes the Runtime Model

When you configure `output: 'standalone'` in [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js), the build process generates a specialized directory structure that differs significantly from the default build output.

The framework creates `.next/standalone` containing only the essential runtime components: the compiled server code, traced `node_modules` dependencies, and a minimal [`package.json`](https://github.com/vercel/next.js/blob/main/package.json). This contrasts with the default behavior where the entire `.next` directory and source tree must be present for `next start` to function.

| Aspect | Default Build | `output: 'standalone'` |
|--------|---------------|------------------------|
| **Entry point** | `next start` reads the full `.next` build and launches [`next-server.js`](https://github.com/vercel/next.js/blob/main/next-server.js) | `next start` prints a warning and exits; you must use `node .next/standalone/server.js` |
| **Configuration loading** | `next start` loads [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js) at runtime | Build writes resolved config to `__NEXT_PRIVATE_STANDALONE_CONFIG`; server reads this JSON |
| **Custom server API** | `import next from 'next'` creates a `NextCustomServer` wrapper | Same wrapper works, but rejects `webpack`, `turbo`, or `turbopack` flags |
| **File availability** | All project files accessible at runtime | Only traced files copied to `standalone` folder; missing imports crash the app |

## Entry Point and Configuration Handling

### The New Binary Entry Point

In [`packages/next/src/server/next.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/next.ts), the framework explicitly checks for standalone mode. If you attempt to run `next start` after a standalone build, the CLI detects this configuration and emits a warning before exiting at lines 319-326:

```typescript
// packages/next/src/server/next.ts#L319-L326
if (process.env.__NEXT_PRIVATE_STANDALONE_CONFIG) {
  console.warn(
    `"next start" does not work with "output: standalone" configuration.\n` +
    `Use "node .next/standalone/server.js" instead.`
  )
  process.exit(0)
}

```

The correct entry point becomes the pre-built binary at [`.next/standalone/server.js`](https://github.com/vercel/next.js/blob/main/.next/standalone/server.js), which contains the fully compiled Next.js server ready for immediate execution.

### Configuration Serialization via Environment Variable

The standalone architecture serializes the resolved configuration to avoid re-executing [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js) at runtime. During the build process, [`packages/next/src/build/utils.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/build/utils.ts) writes the configuration JSON to the environment variable `__NEXT_PRIVATE_STANDALONE_CONFIG` at lines 1465-1475.

At runtime, [`packages/next/src/server/config.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/config.ts) reconstructs the configuration object by parsing this environment variable at lines 1545-1559:

```typescript
// packages/next/src/server/config.ts#L1545-L1559
if (process.env.__NEXT_PRIVATE_STANDALONE_CONFIG) {
  const standaloneConfig = JSON.parse(
    process.env.__NEXT_PRIVATE_STANDALONE_CONFIG
  )
  // Merge standaloneConfig with defaults...
}

```

This mechanism ensures configuration consistency while eliminating the need for the runtime environment to access the original [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js) file.

## Custom Server Compatibility

### Using the Next.js Wrapper API

Custom servers continue to function with `output: 'standalone'` through the standard `next()` wrapper API. In [`packages/next/src/server/next.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/next.ts), the `createServer()` function instantiates `NextCustomServer` when `options.customServer` is true (the default when importing `next` programmatically).

However, the standalone build imposes specific restrictions on server initialization. At lines 48-66 in [`packages/next/src/server/next.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/next.ts), the code validates that certain options are not passed when running in standalone mode:

```typescript
// packages/next/src/server/next.ts#L48-L66
if (options.customServer) {
  // Validate that webpack/turbopack options aren't passed in standalone mode
  if (process.env.__NEXT_PRIVATE_STANDALONE_CONFIG) {
    if (options.webpack || options.turbo || options.turbopack) {
      throw new Error(
        `Cannot use webpack() or turbo() options in custom server with output: 'standalone'`
      )
    }
  }
}

```

### Restricted Bundler Flags

The standalone output pre-compiles all assets during the build phase, making runtime bundler configuration impossible. When using a custom server with `output: 'standalone'`, you cannot pass `webpack`, `turbo`, or `turbopack` options to the `next()` constructor. The framework explicitly throws an error if these options are detected in the standalone environment, as the bundler has already executed and finalized the build artifacts.

## File Tracing and Runtime Isolation

The standalone output relies on aggressive file tracing to determine exactly which files are required at runtime. During the build, [`packages/next/src/build/collect-build-traces.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/build/collect-build-traces.ts) analyzes the server code to generate a manifest of dependencies.

Only files captured by this tracing process are copied into `.next/standalone`. This includes specific `node_modules` files and project assets, but excludes the full source tree. If your custom server or application code performs dynamic imports or requires files not detected by the static analysis, those files will be missing at runtime, causing the server to crash.

This tracing mechanism enables the minimal Docker image size characteristic of standalone deployments, but requires careful attention to dynamic code paths.

## Practical Implementation Examples

### Custom Server with Standalone Output

When using a custom server alongside `output: 'standalone'`, you maintain the standard Next.js wrapper pattern but ensure the server is started via the standalone binary:

```javascript
// server.js (custom server)
import next from 'next';
import http from 'http';

const app = next({ 
  dev: false,
  // Note: cannot use webpack(), turbo(), or turbopack() options here
});

await app.prepare();
const handler = app.getRequestHandler();

http.createServer((req, res) => {
  handler(req, res);
}).listen(3000, () => {
  console.log('> Ready on http://localhost:3000');
});

```

After building, you launch this through the standalone entry point, not `next start`.

### Building and Running the Standalone Server

```bash

# Build the application with standalone output

npm run build

# Correct way to start in production

node .next/standalone/server.js

# Incorrect - will print warning and exit

# next start

```

### Docker Deployment with Custom Server

```dockerfile

# Multi-stage build for minimal standalone image

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build  # Generates .next/standalone

FROM node:20-alpine
WORKDIR /app

# Copy only the standalone output and package.json

COPY --from=builder /app/.next/standalone ./.next/standalone
COPY --from=builder /app/package.json ./

# No source code needed - everything is traced and bundled

CMD ["node", ".next/standalone/server.js"]

```

This configuration eliminates the need for the full Next.js CLI in the production container, running only the compiled standalone binary.

## Summary

- **Entry point change**: `output: 'standalone'` requires starting the application via `node .next/standalone/server.js` instead of `next start`, which explicitly warns and exits in this mode.
- **Configuration serialization**: The build process writes the resolved [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js) to `__NEXT_PRIVATE_STANDALONE_CONFIG`, which the standalone server reads at runtime in [`packages/next/src/server/config.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/config.ts).
- **Custom server restrictions**: While the `next()` wrapper API remains compatible, you cannot pass `webpack`, `turbo`, or `turbopack` options to the custom server when using standalone output, as enforced in [`packages/next/src/server/next.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/next.ts).
- **File tracing isolation**: Only files detected by the build tracer ([`packages/next/src/build/collect-build-traces.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/build/collect-build-traces.ts)) are included in `.next/standalone`, requiring careful handling of dynamic imports.
- **Docker optimization**: The standalone output enables minimal container images by excluding the Next.js CLI and source code, running only the pre-compiled server binary.

## Frequently Asked Questions

### Can I use `next start` with `output: 'standalone'`?

No. When `output: 'standalone'` is configured, running `next start` causes the CLI to print a warning and exit immediately. The code in [`packages/next/src/server/next.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/next.ts) explicitly checks for the `__NEXT_PRIVATE_STANDALONE_CONFIG` environment variable and aborts with instructions to use `node .next/standalone/server.js` instead.

### How does the standalone server load [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js)?

The standalone server does not re-execute [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js) at runtime. During the build, [`packages/next/src/build/utils.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/build/utils.ts) serializes the resolved configuration object and stores it as a JSON string in the `__NEXT_PRIVATE_STANDALONE_CONFIG` environment variable. At runtime, [`packages/next/src/server/config.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/config.ts) parses this variable to reconstruct the configuration, ensuring consistency without requiring the config file in the production environment.

### Can I still use a custom Express server with `output: 'standalone'`?

Yes, custom servers using the `next()` wrapper API remain compatible, but with specific constraints. You can still create a custom server using `import next from 'next'` and `app.getRequestHandler()`, but you must start the application via `node .next/standalone/server.js` rather than your custom server file directly if you want the standalone benefits. Additionally, you cannot pass `webpack`, `turbo`, or `turbopack` options to the `next()` constructor, as these are rejected in [`packages/next/src/server/next.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/next.ts) when running in standalone mode.

### What files are included in the `.next/standalone` folder?

The `.next/standalone` folder contains only the files traced as necessary for runtime execution. During the build, [`packages/next/src/build/collect-build-traces.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/build/collect-build-traces.ts) analyzes the server code to determine exact dependencies. Only the compiled server, specific `node_modules` files, and assets referenced by the tracer are copied. Source files, the full Next.js CLI, and any dynamically imported modules not caught by the static analysis are excluded, which is why dynamic imports require careful handling in standalone deployments.