Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a0daf0a
docs(aws): document the aws-apigw-streaming and aws-lambda-compressed…
vicb Nov 5, 2026
3598469
docs(aws): update the list of wrappers in the components overview
vicb Nov 5, 2026
755fd0c
docs(aws): update the lists of included wrappers, tag caches and queues
vicb Nov 5, 2026
71fb3a2
docs(aws): update the install options
vicb Nov 5, 2026
d5201f1
docs(aws): document routePreloadingBehavior
vicb Nov 5, 2026
dcea1a1
docs(aws): document dangerous.middlewareHeadersOverrideNextConfigHeaders
vicb Nov 5, 2026
e372c0d
docs(aws): document the nextMode tag caches and stale-while-revalidat…
vicb Nov 5, 2026
f6379f7
docs(aws): document native CDN tag invalidation (invalidateTags)
vicb Nov 5, 2026
76c63d6
docs(aws): the sqs queues send messages in the background when waitUn…
vicb Nov 5, 2026
d5e831f
docs(aws): fix the heading of the node converter
vicb Nov 5, 2026
b9cb560
docs(aws): use OPEN_NEXT_BUILD_ID for cache keys
vicb Nov 5, 2026
d0003a1
docs(aws): document the --dangerously-use-unsupported-next-version bu…
vicb Nov 5, 2026
1e6e6e2
docs(aws): document the filtering of non-Linux native binaries
vicb Nov 5, 2026
b458cd8
docs(aws): document OPEN_NEXT_REQUEST_ID_HEADER and OPEN_NEXT_ERROR_L…
vicb Nov 5, 2026
11c23be
docs(aws): document the Cache-Control override for error responses
vicb Nov 5, 2026
8cf0bd4
docs(aws): mention Next.js 16 support on the home page
vicb Nov 5, 2026
0c5fa88
docs(aws): fix the custom asset resolver example to use a LazyLoadedO…
vicb Nov 5, 2026
f39929d
docs(aws): fix the description of the cdnInvalidation override values
vicb Nov 5, 2026
9390992
docs(aws): update the minimum Node.js version
vicb Nov 5, 2026
55ffb52
docs(aws): fix broken links
vicb Nov 5, 2026
fcef760
docs(aws): document when Queue.send is called and when it should resolve
vicb Nov 13, 2026
1dd8f77
docs(aws): document lastModified and eTag in the revalidation queue m…
vicb Nov 13, 2026
f2cd7b8
docs(aws): clarify that deploymentId is used as the build id for ever…
vicb Nov 13, 2026
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
8 changes: 8 additions & 0 deletions pages/aws/common_issues.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ This will output **A LOT** of additional logs to the console.This also disable m
OPEN_NEXT_DEBUG=true npx open-next@latest build
```

A few other environment variables can help debugging at runtime:

- `OPEN_NEXT_REQUEST_ID_HEADER` - When set, the `x-opennext-requestid` header is added to the responses (it is always added in debug mode). Available since `@opennextjs/aws` 3.7.0.
- `OPEN_NEXT_ERROR_LOG_LEVEL` - The minimum level of the internal OpenNext errors that are logged: `0` (or `debug`), `1` (or `warn`, the default) or `2` (or `error`).

#### Cannot find module next

You might stumble upon this error inside cloudwatch logs: `Cannot find module 'next'`. It is likely that you are in a monorepo and you have several lock files. **Just make sure that you have a single lock file in the root of your project.**
Expand All @@ -32,6 +37,9 @@ You should also not add sharp as a dependency unless absolutely necessary, the i
- `next/dist/compiled/babel-packages`
- `next/dist/compiled/amphtml-validator`

Since `@opennextjs/aws` 3.10.0, OpenNext also excludes the platform specific native binaries for non-Linux platforms (i.e. `@swc/core-darwin-arm64`) that are traced when building on macOS or Windows.
You can set the `OPEN_NEXT_SKIP_PLATFORM_FILTER` environment variable to `true` at build time to disable this filter.

##### Remove sourcemaps

Source maps could add a lot to the bundle, excluding them from standalone output could be worth it.
Expand Down
3 changes: 2 additions & 1 deletion pages/aws/config.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
### Build Arguments

There is two build arguments that you can pass to the `open-next build` command:
These are the build arguments that you can pass to the `open-next build` command:

- `--config-path` - This is the path to the configuration file that you want to use. By default, it will look for `open-next.config.ts` in the current working directory. This needs to be relative to the current working directory.
- `--node-externals` - You can configure externals for the esbuild compilation of the `open-next.config.ts` file (i.e `--node-externals @aws-sdk/*,open-next/dist/queue/*`)
- `--dangerously-use-unsupported-next-version` - Since `@opennextjs/aws` 3.9.13, the build fails when the Next.js version is no longer supported by the Next.js team (see the [Next.js support policy](https://nextjs.org/support-policy)) as it may contain unpatched security vulnerabilities. This flag allows building anyway.

### Configuration File

Expand Down
4 changes: 2 additions & 2 deletions pages/aws/config/custom_overrides.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ const config = {
export default config;
```

[Included](https://github.com/opennextjs/opennextjs-aws/tree/main/packages/open-next/src/overrides/tagCache) ones are `'dynamodb' | 'dynamodb-lite' | 'fs-dev' | 'dummy'`
[Included](https://github.com/opennextjs/opennextjs-aws/tree/main/packages/open-next/src/overrides/tagCache) ones are `'dynamodb' | 'dynamodb-lite' | 'dynamodb-nextMode' | 'fs-dev' | 'fs-dev-nextMode' | 'dummy'`

## Custom Origin Resolver

Expand Down Expand Up @@ -418,7 +418,7 @@ import type { OpenNextConfig } from "@opennextjs/aws/types/open-next.js";
const config = {
default: {},
middleware: {
assetResolver: import("./customAssetResolver").then((mod) => mod.default),
assetResolver: () => import("./customAssetResolver").then((mod) => mod.default),
},
} satisfies OpenNextConfig;

Expand Down
28 changes: 28 additions & 0 deletions pages/aws/config/overrides/automatic_cdn_invalidation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,34 @@ It will be called for `revalidatePath`, `revalidateTag` and `res.revalidate()`.

If you want to better understand how to implement your own Automatic CDN Invalidation, the easiest way would be to take a look at the existing [included Automatic CDN Invalidation](https://github.com/opennextjs/opennextjs-aws/tree/main/packages/open-next/src/overrides/cdnInvalidation)

## Custom implementations

An Automatic CDN Invalidation override must implement `invalidatePaths` and can optionally implement `invalidateTags`:

```ts
type CDNInvalidationHandler = {
name: string;
invalidatePaths: (paths: CDNPath[]) => Promise<void>;
invalidateTags?: (tags: string[]) => Promise<void>;
};
```

### `invalidatePaths`

Invalidates the CDN entries of the given paths. Each path includes the path before (`initialPath`) and after (`rawPath`) routing as well as the routes that matched while resolving the request (`resolvedRoutes`).

For `revalidateTag` and `revalidatePath`, the paths are resolved from the tags by the [Tag Cache](/aws/config/overrides/tag_cache). Tag caches in `nextMode` can only resolve paths when they implement the optional `getPathsByTags` method.

### `invalidateTags`

Available since `@opennextjs/aws` 4.1.14

If your CDN supports invalidating its cache by tags, you can implement `invalidateTags` to invalidate the original cache tags directly instead of resolving them to paths.

- It is called once per `revalidateTag` or `revalidatePath` call, after the tag cache has been updated, with the tags as passed to Next.js: hard tags from `revalidateTag()` and soft tags (prefixed with `_N_T_/`) from `revalidatePath()`. Tags are not expanded, i.e. the hard tags of the paths matching a soft tag are not added.
- When it is provided, `invalidatePaths` is no longer called for `revalidateTag` and `revalidatePath`. It is still called for `res.revalidate()` in the Pages Router.
- The CDN integration must associate cached entries with the same tags, both hard and soft, for the invalidation to have an effect.

## Included Automatic CDN Invalidation

### dummy
Expand Down
2 changes: 1 addition & 1 deletion pages/aws/config/overrides/converter.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The `aws-cloudfront` Converter is a converter for Cloudfront (i.e. lambda@edge)

The `edge` Converter is the converter for everything that uses `Request` and `Response`. At the moment with the builtin one that's only Cloudflare.

### converter
### node

The `node` Converter is a converter for classic Node.js server.

Expand Down
2 changes: 2 additions & 0 deletions pages/aws/config/overrides/incremental_cache.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ If you want to better understand how to implement your own IncrementalCache, the

One thing to note is that it is not used at build time, only at runtime. This means that you'll have to upload the cache yourself if you want to use the prebuilt routes/pages (And this is mandatory for ISR/SSG routes with `fallback:false`).
All the cache files are present in the `.open-next/cache` folder. The one under `BUILD_ID` are for the ISR/SSG cache and the one under `__fetch/BUILD_ID` are for the fetch cache.
`BUILD_ID` is the OpenNext build id (`process.env.OPEN_NEXT_BUILD_ID` at runtime): the Next.js [`deploymentId`](https://nextjs.org/docs/app/api-reference/config/next-config-js/deploymentId) when set and the Next.js build id otherwise.
Comment thread
vicb marked this conversation as resolved.
Resolved
This applies to every supported Next.js version. It matters most on Next.js 16.2+, where the Next.js build id is the same for every deployment when `deploymentId` is set.

## Included IncrementalCache

Expand Down
12 changes: 10 additions & 2 deletions pages/aws/config/overrides/queue.mdx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { Callout } from "nextra/components";

This override is used by OpenNext to trigger the revalidation of stale routes.
Before sending the response to the client, OpenNext will check if the route is stale and if it is, it will call the queue override to revalidate the route.
When a stale route is served, OpenNext calls the `send` method of the queue override to revalidate the route:

- When the route is rendered by the Next server, `send` is called once the response is sent (in `waitUntil` when the wrapper provides one).
- With [cache interception](/aws/inner_workings/cache_interception), `send` is awaited before the stale response is returned. If it throws, the error is logged and the request falls back to the Next server.

If you want to better understand how to implement your own Queue, the easiest way would be to take a look at the existing [included Queue](https://github.com/opennextjs/opennextjs-aws/tree/main/packages/open-next/src/overrides/queue).

Couple of things to note :

- The default implementation use an SQS queue. This has the main advantage of being able to control the concurrency of the revalidations as well as avoiding trigerring the revalidation multiple times for the same route.
- The promise returned by `send` should resolve once the message is accepted (or handed to `waitUntil`), not once the route is revalidated, so that the response is not delayed.
- You don't have to use a queue at all. You could trigger the revalidation directly in the Queue override itself. You can see a very simple implementation of this [in the `direct` override](https://github.com/opennextjs/opennextjs-aws/blob/main/packages/open-next/src/overrides/queue/direct.ts).

## Included Queue
Expand All @@ -17,6 +21,8 @@ Couple of things to note :
The SQS Queue will send a message to an SQS queue for each route that needs to be revalidated. It is used by default if you don't provide any Queue in your configuration.
It uses the `@aws-sdk/client-sqs` to interact with SQS.

Since `@opennextjs/aws` 4.1.6, the message is sent in the background when the wrapper provides a `waitUntil` (i.e. `aws-lambda-streaming` or `aws-apigw-streaming`) so that it does not delay the response. Otherwise, the response is sent once the message has been sent. The same applies to `sqs-lite`.

#### Requirements

- You need to provide the `REVALIDATION_QUEUE_URL` environment variable to your server.
Expand All @@ -35,7 +41,9 @@ This implementation is a lighter version of the `sqs` Queue as it uses `aws4fetc
The Direct Queue will directly trigger the revalidation of the route in the Queue override itself. It is useful for development purposes and when you don't want to use a queue.

<Callout type="warning">
Be careful with this implementation as it could lead to multiple revalidations of the same route.
Be careful with this implementation as it could lead to multiple revalidations of the same route. As `send`
resolves once the route is revalidated, it also delays the stale response when cache interception is
enabled.
</Callout>

### dummy
Expand Down
42 changes: 39 additions & 3 deletions pages/aws/config/overrides/tag_cache.mdx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Callout } from "nextra/components";

This override is used by the [`cache` adapter](https://github.com/opennextjs/opennextjs-aws/blob/main/packages/open-next/src/adapters/cache.ts) that is provided by OpenNext to the NextServer. It is also used by OpenNext if `enableCacheInterception` is set to `true` in the configuration and by the `initializationFunction` for prepopulating the cache.

It is used for the cache tags (i.e. `revalidateTag` and `revalidatePath`). It does not handle anything related to the ISR/SSG cache or the fetch cache used by Next.js.
Expand All @@ -7,9 +9,33 @@ The current implementation differs from the way Next.js standalone handle cache
We choose to go another way. We store tags for every path that exists in the cache. This way, we can easily know if a path is stale by just checking the path instead of every tags used. This approach is more write heavy but it's a tradeoff we are willing to make.
This also has the drawback of needing to prepopulate the cache with all the tags that are used in the application. This is done by the `initializationFunction`.

We might allow to choose how cache tags are handled in the future depending on the `TagCache` implementation. If you need this feature, feel free to open an issue on the [GitHub repository](https://github.com/opennextjs/opennextjs-aws).
## Modes

A `TagCache` can work in one of two modes, set with its `mode` property:

- `original` (default) - The approach described above. Tags are stored for every path, so a single lookup per path is needed on read. It needs to be prepopulated at build time and is write heavy. It allows the [automatic CDN invalidation](/aws/config/overrides/automatic_cdn_invalidation) to resolve the paths of a tag.
- `nextMode` - Similar to the way Next.js handles tags. Only the time at which a tag has been revalidated is stored, and every tag of an entry is checked on read. It doesn't need to be prepopulated and writes very little, but reads more. Path resolution for the automatic CDN invalidation is only available when the implementation provides the optional `getPathsByTags` method.

## Custom implementations

If you want to better understand how to implement your own TagCache, the easiest way would be to take a look at the existing [included TagCache](https://github.com/opennextjs/opennextjs-aws/tree/main/packages/open-next/src/overrides/tagCache) and at the [types](https://github.com/opennextjs/opennextjs-aws/blob/main/packages/open-next/src/types/overrides.ts).

### Stale-while-revalidate

Since `@opennextjs/aws` 3.10.0, `revalidateTag(tag, profile)` (Next.js 16+) can mark the entries as stale instead of expiring them right away. Stale entries are still served while they are revalidated in the background.

To support it, a `TagCache` must store the optional `stale` and `expire` timestamps (in milliseconds since epoch) passed to `writeTags` and implement the optional `isStale` method:

- `original` mode: `isStale(path: string, lastModified?: number): Promise<boolean>`
- `nextMode`: `isStale(tags: string[], lastModified?: number): Promise<boolean>`

If you want to better understand how to implement your own TagCache, the easiest way would be to take a look at the existing [included TagCache](https://github.com/opennextjs/opennextjs-aws/tree/main/packages/open-next/src/overrides/tagCache).
Without `isStale`, stale entries are not detected, only expired ones are.

<Callout type="warning">
The signature of `writeTags` changed in `@opennextjs/aws` 3.10.0. It now receives `OriginalTagCacheWriteInput[]`
(`{ tag, path, revalidatedAt?, stale?, expire? }`) in the `original` mode and `NextModeTagCacheWriteInput[]`
(`string | { tag, stale?, expire? }`) in `nextMode`. Custom implementations must be updated.
</Callout>

## Included TagCache

Expand All @@ -35,7 +61,13 @@ This implementation is a lighter version of the `dynamodb` TagCache as it uses `

### dynamodb-nextMode

TBA
The DynamoDBNextMode TagCache will store the time at which each tag has been revalidated in a DynamoDB table. It works in `nextMode` and uses `aws4fetch` to interact with DynamoDB.
It doesn't need to be prepopulated by the `initializationFunction`, and it doesn't support resolving the paths of a tag for the automatic CDN invalidation.

##### Requirements

- You need to provide the `CACHE_DYNAMO_TABLE`, `CACHE_BUCKET_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_SESSION_TOKEN` environment variables to your server.
- DynamoDB table should have a primary key `path` of type `String` and a sort key `tag` of type `String`. (It can reuse the same table as the one used by the default `tagCache`)

### dummy

Expand All @@ -44,3 +76,7 @@ The Dummy TagCache is a dummy implementation that will throw an exception. It sh
### fs-dev

The FsDev TagCache is a simple implementation that stores the cache tags in a file in the `.open-next/cache` folder and interact with it using the filesystem. It is useful for development purposes only.

### fs-dev-nextMode

The FsDevNextMode TagCache is a simple implementation that works in `nextMode` and stores the cache tags in memory. It is useful for development purposes only.
40 changes: 38 additions & 2 deletions pages/aws/config/overrides/wrapper.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Couple of things to note :
- If you want to use streaming (for the `node` runtime of next), you'll need to create a `StreamCreator` and pass it to the `handler`. You can find some example in the [node](https://github.com/opennextjs/opennextjs-aws/blob/main/packages/open-next/src/overrides/wrappers/node.ts) or [aws-lambda-streaming](https://github.com/opennextjs/opennextjs-aws/blob/main/packages/open-next/src/overrides/wrappers/aws-lambda-streaming.ts) wrapper.
- If you don't use streaming (like in the default `aws-lambda` wrapper), you may still need to provide a fake `StreamCreator` to the `handler` to avoid a weird issue with Node itself (see [here](https://github.com/opennextjs/opennextjs-aws/blob/f685ddea8f8a5c82591dc02713aff7138f2d9896/packages/open-next/src/overrides/wrappers/aws-lambda.ts#L49-L65) for an example and a more thorough explanation).
- If you use the `edge` runtime of Next (either for the external middleware or for an `edge` route or page), you don't need the `StreamCreator` at all.
- If you are in a serverless environment and it supports `waitUntil`, you should pass it to the handler as it is done in the [cloudflare-edge wrapper](https://github.com/opennextjs/opennextjs-aws/blob/87b59e59a8a0bf1e83d2d1df9efa0ad3bfc912f5/packages/open-next/src/overrides/wrappers/cloudflare-edge.ts#L65-L67). This might not be necessary depending on where you run it (for example the `aws-lambda-streaming` or the `node` wrapper doesn't need it.)
- If you are in a serverless environment and it supports `waitUntil`, you should pass it to the handler as it is done in the [cloudflare-edge wrapper](https://github.com/opennextjs/opennextjs-aws/blob/87b59e59a8a0bf1e83d2d1df9efa0ad3bfc912f5/packages/open-next/src/overrides/wrappers/cloudflare-edge.ts#L65-L67). The `aws-lambda-streaming` and `aws-apigw-streaming` wrappers provide their own `waitUntil` (pending promises are awaited before the response stream is closed). This might not be necessary depending on where you run it (for example the `node` wrapper doesn't need it as it is a long running server.)

## Included Wrappers

Expand All @@ -22,12 +22,48 @@ The `aws-lambda` Wrapper is the default wrapper for AWS Lambda. It is used by de

### aws-lambda-streaming

The `aws-lambda-streaming` Wrapper is a wrapper that allows you to use streaming in AWS Lambda. Streaming must be enabled for this lambda.
The `aws-lambda-streaming` Wrapper is a wrapper that allows you to use streaming in AWS Lambda. Streaming must be enabled for this lambda and it must be invoked through a Lambda Function URL.

The response is compressed (`br`, `gzip` or `deflate`) according to the `Accept-Encoding` header of the request.

#### Features

- [x] Streaming
- [x] Proper support for `waitUntil` (available since `@opennextjs/aws` 4.1.6)
- [x] Compression

### aws-apigw-streaming

Available since `@opennextjs/aws` 4.1.0

The `aws-apigw-streaming` Wrapper allows you to use streaming when the server function is behind an [API Gateway REST API with response streaming](https://aws.amazon.com/about-aws/whats-new/2025/11/api-gateway-response-streaming-rest-apis/) (`ResponseTransferMode: STREAM`) instead of a Lambda Function URL.

It should be used with the `aws-apigw-v1` (REST API) or `aws-apigw-v2` (HTTP API) converter.

Unlike `aws-lambda-streaming`, it never compresses the response because API Gateway streaming does not support content encoding. Compression should be handled by the CDN in front of API Gateway (e.g. CloudFront).

#### Features

- [x] Streaming
- [x] Proper support for `waitUntil`
- [ ] Compression

### aws-lambda-compressed

Available since `@opennextjs/aws` 3.5.6

The `aws-lambda-compressed` Wrapper is the same as the `aws-lambda` Wrapper but it also compresses the response (`br`, `gzip` or `deflate`) according to the `Accept-Encoding` header of the request.
It can be useful to reduce the size of the response as AWS Lambda has a limit of 6MB for the response payload.

#### Features

- [ ] Streaming
- [ ] Proper support for `waitUntil`
- [x] Compression

### Compression

The Brotli compression quality used by the `aws-lambda-streaming` and `aws-lambda-compressed` wrappers can be set with the `BROTLI_QUALITY` environment variable (from `0` to `11`). It defaults to `6`.

### cloudflare-edge

Expand Down
Loading
Loading