Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions docs/01-app/02-guides/data-security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -399,9 +399,15 @@ However, for this to happen, the captured variables are sent to the client and b

When **self-hosting** your Next.js application across multiple servers, each server instance may end up with a different encryption key, leading to potential inconsistencies.

To mitigate this, you can overwrite the encryption key using the `process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` environment variable. Specifying this variable ensures that your encryption keys are persistent across builds, and all server instances use the same key. This variable **must** be AES-GCM encrypted.
To mitigate this, you can overwrite the encryption key using the `process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` environment variable. Specifying this variable ensures that your encryption keys are persistent across builds, and all server instances use the same key.

This is an advanced use case where consistent encryption behavior across multiple deployments is critical for your application. You should consider standard security practices such key rotation and signing.
The key must be a base64-encoded value whose decoded length matches a valid AES key size (16, 24, or 32 bytes). Next.js generates 32-byte keys by default. You can generate a compatible key using your platform’s cryptographic tools, for example:

```bash
openssl rand -base64 32
```

This is an advanced use case where consistent encryption behavior across multiple deployments is critical for your application. Follow standard security practices such as key rotation and signing. See the [Self-Hosting guide](/docs/app/guides/self-hosting#server-functions-encryption-key) for deployment-specific considerations.

### Allowed origins (advanced)

Expand Down
48 changes: 46 additions & 2 deletions docs/01-app/02-guides/self-hosting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,55 @@ module.exports = {
}
```

## Multi-Server Deployments

When running Next.js across multiple server instances (for example, containers behind a load balancer), there are additional considerations to ensure consistent behavior.

### Server Functions encryption key

Next.js encrypts [Server Function](/docs/app/getting-started/updating-data) closure variables before sending them to the client. By default, a unique encryption key is generated for each build.

When running multiple server instances, all instances must use the same encryption key. Otherwise, a Server Function encrypted by one instance cannot be decrypted by another, causing "Failed to find Server Action" errors.

Set a consistent encryption key using the `NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` environment variable. The key must be a base64-encoded value with a valid AES key length (16, 24, or 32 bytes). Next.js generates 32-byte keys by default.

```bash
NEXT_SERVER_ACTIONS_ENCRYPTION_KEY=your-generated-key next build
```

The key is embedded in the build output and used automatically at runtime. Learn more in the [Data Security guide](/docs/app/guides/data-security#overwriting-encryption-keys-advanced).

### Deployment identifier

Configure a [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) to enable version skew protection during rolling deployments. This ensures clients always receive assets from a consistent deployment version.

### Shared cache

By default, Next.js uses an in-memory cache that is not shared across instances. For consistent caching behavior, use [`'use cache: remote'`](/docs/app/api-reference/directives/use-cache-remote) with a [custom cache handler](/docs/app/api-reference/config/next-config-js/cacheHandlers) that stores data in external storage.

## Version Skew

Next.js will automatically mitigate most instances of [version skew](https://www.industrialempathy.com/posts/version-skew/) and automatically reload the application to retrieve new assets when detected. For example, if there is a mismatch in the `deploymentId`, transitions between pages will perform a hard navigation versus using a prefetched value.
When self-hosting across multiple instances or doing rolling deployments, [version skew](/docs/app/glossary#version-skew) can cause:

- **Missing assets**: The client requests JavaScript or CSS files that no longer exist on the server
- **Server Function mismatches**: The client invokes a Server Function using an ID from a previous build that the server no longer recognizes
- **Navigation failures**: Prefetched page data from an old deployment is incompatible with the new server

Next.js uses the [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) to detect and handle version skew. When a deployment ID is configured:

- Static assets include a `?dpl=<deploymentId>` query parameter
- Client-side navigation requests include an `x-deployment-id` header
- The server compares the client's deployment ID with its own
Comment on lines +219 to +221
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this list exists two times now?

once here and then another time (slightly differently) in docs/01-app/03-api-reference/05-config/01-next-config-js/deploymentId.mdx

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think that's OK, because it is a Guide vs API Reference


If a mismatch is detected, Next.js triggers a hard navigation (full page reload) instead of a client-side navigation. This ensures the client fetches assets from a consistent deployment version.

```js filename="next.config.js"
module.exports = {
deploymentId: process.env.DEPLOYMENT_VERSION,
}
```

When the application is reloaded, there may be a loss of application state if it's not designed to persist between page navigations. For example, using URL state or local storage would persist state after a page refresh. However, component state like `useState` would be lost in such navigations.
> **Good to know:** When the application is reloaded, there may be a loss of application state if it's not designed to persist between page navigations. URL state or local storage would persist, but component state like `useState` would be lost.

<AppOnly>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title: deploymentId
description: Configure a deployment identifier used for version skew protection and cache busting.
---

{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}

The `deploymentId` option allows you to set an identifier for your deployment. This identifier is used for [version skew](/docs/app/guides/self-hosting#version-skew) protection and cache busting during rolling deployments.

```js filename="next.config.js"
module.exports = {
deploymentId: 'my-deployment-id',
}
```

You can also set the deployment ID using the `NEXT_DEPLOYMENT_ID` environment variable:

```bash
NEXT_DEPLOYMENT_ID=my-deployment-id next build
```

> **Good to know:** If both are set, the `deploymentId` value in `next.config.js` takes precedence over the `NEXT_DEPLOYMENT_ID` environment variable.

## How it works

When a `deploymentId` is configured, Next.js:

1. Appends `?dpl=<deploymentId>` to static asset URLs (JavaScript, CSS, images)
2. Adds an `x-deployment-id` header to client-side navigation requests
3. Adds an `x-nextjs-deployment-id` header to navigation responses
4. Injects a `data-dpl-id` attribute on the `<html>` element

When the client detects a mismatch between its deployment ID and the server's (via the response header), it triggers a hard navigation (full page reload) instead of a client-side navigation. This ensures users always receive assets <AppOnly>and Server Functions</AppOnly> from a consistent deployment version.

> **Good to know:** Next.js does not read the `?dpl=` query parameter on incoming requests. The query parameter is for cache busting (ensuring browsers and CDNs fetch fresh assets), not for routing. If you need version-aware routing, consult your hosting provider or CDN's documentation for implementing deployment-based routing.

## Use cases

### Rolling deployments

During a rolling deployment, some server instances may be running the new version while others are still running the old version. Without a deployment ID, users might receive a mix of old and new assets, causing errors.

Setting a consistent `deploymentId` per deployment ensures:

<AppOnly>

- Clients always request assets from a matching deployment version
- Mismatches trigger a full reload to fetch the correct assets
- Server Functions work correctly across deployment boundaries

</AppOnly>

<PagesOnly>

- Clients always request assets from a matching deployment version
- Mismatches trigger a full reload to fetch the correct assets

</PagesOnly>

### Multi-server environments

When running multiple instances of your Next.js application behind a load balancer, all instances for the same deployment should use the same `deploymentId`.

```js filename="next.config.js"
module.exports = {
deploymentId: process.env.DEPLOYMENT_VERSION || process.env.GIT_SHA,
}
```

## Version History

| Version | Changes |
| ---------- | ----------------------------------------------------- |
| `v14.1.4` | `deploymentId` stabilized as top-level config option. |
| `v13.4.10` | `experimental.deploymentId` introduced. |

## Related

- [Self-Hosting - Version Skew](/docs/app/guides/self-hosting#version-skew)
- [generateBuildId](/docs/app/api-reference/config/next-config-js/generateBuildId)
6 changes: 6 additions & 0 deletions docs/01-app/04-glossary.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,9 @@ A special React directive that marks the boundary between server and client code
## `"use server"` Directive

A directive that marks a function as a [Server Function](#server-function) that can be called from client-side code. It can be placed at the top of a file to indicate that all exports in the file are Server Functions, or inline at the top of a function to mark that specific function. Learn more in the [`"use server"` reference](/docs/app/api-reference/directives/use-server).

# V

## Version skew

After a new version of your application is deployed, clients that are still active may reference JavaScript, CSS, or data from an older build. This mismatch between client and server versions is called version skew, and it can cause missing assets, Server Action errors, and navigation failures. Next.js uses [`deploymentId`](/docs/app/api-reference/config/next-config-js/deploymentId) to detect and handle version skew. Learn more in [Self-Hosting - Version Skew](/docs/app/guides/self-hosting#version-skew).
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: deploymentId
description: Configure a deployment identifier used for version skew protection and cache busting.
source: app/api-reference/config/next-config-js/deploymentId
---

{/* DO NOT EDIT. The content of this doc is generated from the source above. To edit the content of this page, navigate to the source page in your editor. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
4 changes: 3 additions & 1 deletion errors/failed-to-find-server-action.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ When self-hosting your Next.js application across multiple servers, each server

## Possible Ways to Fix It

To mitigate this, you can overwrite the encryption key using the `process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` environment variable. Specifying this variable ensures that your encryption keys are persistent across builds, and all server instances use the same key. This variable **must** be AES-GCM encrypted.
To mitigate this, you can overwrite the encryption key using the `process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` environment variable. Specifying this variable ensures that your encryption keys are persistent across builds, and all server instances use the same key.

The key must be a base64-encoded value with a valid AES key length (16, 24, or 32 bytes). Set this variable at **build time**—the key is embedded in the build output and used automatically at runtime.

If you are deploying your Next.js application to Vercel, you can use the feature [Skew Protection](https://vercel.com/docs/deployments/skew-protection) to ensure assets and functions from the previous version are still available, even after a new version is deployed.

Expand Down
Loading