cdk-nextjs 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +2404 -2723
- package/.jsii.tabl.json +1 -1
- package/API.md +1681 -1930
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +667 -4
- package/docs/caching-guide.md +156 -112
- package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
- package/docs/development-guide.md +1 -1
- package/docs/harness-coverage.md +598 -0
- package/docs/init-cache-deployment.md +32 -1
- package/docs/next-build-output-guide.md +30 -20
- package/examples/README.md +5 -1
- package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
- package/lib/adapter/__fixtures__/app-playground.json +4917 -0
- package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
- package/lib/adapter/adapter.mjs +1548 -185
- package/lib/adapter/adapter.test.js +106 -0
- package/lib/adapter/aws-cache-store.d.ts +489 -0
- package/lib/adapter/aws-cache-store.js +1004 -0
- package/lib/adapter/aws-cache-store.test.d.ts +1 -0
- package/lib/adapter/aws-cache-store.test.js +361 -0
- package/lib/adapter/build-outputs.d.ts +80 -0
- package/lib/adapter/build-outputs.js +852 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +861 -0
- package/lib/adapter/cache-handler.d.ts +9 -2
- package/lib/adapter/cache-handler.js +72 -96
- package/lib/adapter/cache-handler.mjs +18956 -17774
- package/lib/adapter/cache-handler.test.js +263 -31
- package/lib/adapter/cache-kinds.d.ts +32 -0
- package/lib/adapter/cache-kinds.js +35 -0
- package/lib/adapter/cache-kinds.test.d.ts +1 -0
- package/lib/adapter/cache-kinds.test.js +69 -0
- package/lib/adapter/cache-utils.d.ts +90 -0
- package/lib/adapter/cache-utils.js +199 -4
- package/lib/adapter/cache-utils.test.d.ts +1 -0
- package/lib/adapter/cache-utils.test.js +179 -0
- package/lib/adapter/function-groups.d.ts +215 -0
- package/lib/adapter/function-groups.js +1099 -0
- package/lib/adapter/function-groups.test.d.ts +1 -0
- package/lib/adapter/function-groups.test.js +743 -0
- package/lib/adapter/init-cache.d.ts +6 -0
- package/lib/adapter/init-cache.js +245 -0
- package/lib/adapter/init-cache.test.d.ts +1 -0
- package/lib/adapter/init-cache.test.js +137 -0
- package/lib/adapter/local-file-cache-handler.d.ts +23 -0
- package/lib/adapter/local-file-cache-handler.js +52 -1
- package/lib/adapter/memory-cache-handler.d.ts +26 -17
- package/lib/adapter/memory-cache-handler.js +32 -50
- package/lib/adapter/memory-cache-handler.test.js +105 -85
- package/lib/adapter/s3-cache-handler.d.ts +179 -40
- package/lib/adapter/s3-cache-handler.js +807 -277
- package/lib/adapter/s3-cache-handler.test.js +1186 -31
- package/lib/adapter/use-cache-common.d.ts +90 -0
- package/lib/adapter/use-cache-common.js +250 -0
- package/lib/adapter/use-cache-common.test.d.ts +1 -0
- package/lib/adapter/use-cache-common.test.js +646 -0
- package/lib/adapter/use-cache-default-handler.d.ts +24 -0
- package/lib/adapter/use-cache-default-handler.js +90 -0
- package/lib/adapter/use-cache-default-handler.mjs +38645 -0
- package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
- package/lib/adapter/use-cache-handlers.test.js +349 -0
- package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
- package/lib/adapter/use-cache-remote-handler.js +186 -0
- package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
- package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
- package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
- package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
- package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +8 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
- package/lib/index.d.ts +6 -7
- package/lib/index.js +2 -4
- package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
- package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
- package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
- package/lib/lambdas/post-deploy/prune-s3.js +41 -12
- package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
- package/lib/nextjs-api.d.ts +102 -18
- package/lib/nextjs-api.js +338 -38
- package/lib/nextjs-api.test.js +537 -1
- package/lib/nextjs-build/global-containers.Dockerfile +15 -10
- package/lib/nextjs-build/nextjs-build.d.ts +339 -63
- package/lib/nextjs-build/nextjs-build.js +684 -327
- package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
- package/lib/nextjs-build/nextjs-build.test.js +412 -0
- package/lib/nextjs-build/patch-fetch.js +1 -1
- package/lib/nextjs-build/patch-fetch.test.js +166 -11
- package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
- package/lib/nextjs-cache.d.ts +82 -4
- package/lib/nextjs-cache.js +186 -10
- package/lib/nextjs-cache.test.js +176 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
- package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
- package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
- package/lib/nextjs-compute/nextjs-containers.js +57 -20
- package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
- package/lib/nextjs-compute/nextjs-functions.js +113 -67
- package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
- package/lib/nextjs-distribution.d.ts +194 -23
- package/lib/nextjs-distribution.js +535 -62
- package/lib/nextjs-distribution.test.d.ts +1 -0
- package/lib/nextjs-distribution.test.js +697 -0
- package/lib/nextjs-post-deploy.d.ts +13 -5
- package/lib/nextjs-post-deploy.js +13 -10
- package/lib/nextjs-post-deploy.test.d.ts +1 -0
- package/lib/nextjs-post-deploy.test.js +34 -0
- package/lib/nextjs-static-assets.d.ts +17 -4
- package/lib/nextjs-static-assets.js +22 -5
- package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
- package/lib/root-constructs/nextjs-base-construct.js +139 -47
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -71
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -70
- package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
- package/lib/root-constructs/nextjs-regional-containers.js +8 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -26
- package/lib/runtime/api-gateway-path.d.ts +34 -0
- package/lib/runtime/api-gateway-path.js +71 -0
- package/lib/runtime/api-gateway-path.test.d.ts +1 -0
- package/lib/runtime/api-gateway-path.test.js +65 -0
- package/lib/runtime/case-redirect.d.ts +22 -0
- package/lib/runtime/case-redirect.js +63 -0
- package/lib/runtime/case-redirect.test.d.ts +1 -0
- package/lib/runtime/case-redirect.test.js +32 -0
- package/lib/runtime/core.d.ts +234 -0
- package/lib/runtime/core.js +1213 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1678 -0
- package/lib/runtime/deployment-root.d.ts +13 -0
- package/lib/runtime/deployment-root.js +29 -0
- package/lib/runtime/dispatch.d.ts +331 -0
- package/lib/runtime/dispatch.js +751 -0
- package/lib/runtime/dispatch.test.d.ts +1 -0
- package/lib/runtime/dispatch.test.js +853 -0
- package/lib/runtime/entrypoints.d.ts +57 -0
- package/lib/runtime/entrypoints.js +115 -0
- package/lib/runtime/http/abort-signal.d.ts +6 -0
- package/lib/runtime/http/abort-signal.js +19 -0
- package/lib/runtime/http/abort-signal.test.d.ts +1 -0
- package/lib/runtime/http/abort-signal.test.js +49 -0
- package/lib/runtime/http/node-server.d.ts +38 -0
- package/lib/runtime/http/node-server.js +99 -0
- package/lib/runtime/http/node-server.test.d.ts +1 -0
- package/lib/runtime/http/node-server.test.js +96 -0
- package/lib/runtime/http/node-sink.d.ts +16 -0
- package/lib/runtime/http/node-sink.js +48 -0
- package/lib/runtime/http/node-sink.test.d.ts +1 -0
- package/lib/runtime/http/node-sink.test.js +66 -0
- package/lib/runtime/http/request.d.ts +62 -0
- package/lib/runtime/http/request.js +134 -0
- package/lib/runtime/http/request.test.d.ts +1 -0
- package/lib/runtime/http/request.test.js +103 -0
- package/lib/runtime/http/response.d.ts +77 -0
- package/lib/runtime/http/response.js +229 -0
- package/lib/runtime/http/response.test.d.ts +1 -0
- package/lib/runtime/http/response.test.js +178 -0
- package/lib/runtime/http/sink.d.ts +73 -0
- package/lib/runtime/http/sink.js +188 -0
- package/lib/runtime/http/sink.test.d.ts +1 -0
- package/lib/runtime/http/sink.test.js +257 -0
- package/lib/runtime/image-utils.d.ts +78 -0
- package/lib/runtime/image-utils.js +129 -0
- package/lib/runtime/image-utils.test.d.ts +1 -0
- package/lib/runtime/image-utils.test.js +237 -0
- package/lib/runtime/image.d.ts +76 -0
- package/lib/runtime/image.js +296 -0
- package/lib/runtime/image.test.d.ts +1 -0
- package/lib/runtime/image.test.js +405 -0
- package/lib/runtime/lambda-event.d.ts +4 -0
- package/lib/runtime/lambda-event.js +113 -0
- package/lib/runtime/lambda-event.test.d.ts +1 -0
- package/lib/runtime/lambda-event.test.js +119 -0
- package/lib/runtime/lambda.mjs +41595 -0
- package/lib/runtime/load-module.d.ts +8 -0
- package/lib/runtime/load-module.js +35 -0
- package/lib/runtime/manifest.d.ts +215 -0
- package/lib/runtime/manifest.js +118 -0
- package/lib/runtime/middleware.d.ts +43 -0
- package/lib/runtime/middleware.js +113 -0
- package/lib/runtime/middleware.test.d.ts +1 -0
- package/lib/runtime/middleware.test.js +259 -0
- package/lib/runtime/next-modules.d.ts +55 -0
- package/lib/runtime/next-modules.js +124 -0
- package/lib/runtime/next-modules.test.d.ts +1 -0
- package/lib/runtime/next-modules.test.js +34 -0
- package/lib/runtime/public-files.d.ts +32 -0
- package/lib/runtime/public-files.js +117 -0
- package/lib/runtime/public-files.test.d.ts +1 -0
- package/lib/runtime/public-files.test.js +97 -0
- package/lib/runtime/server.mjs +41588 -0
- package/lib/runtime/static-files.d.ts +50 -0
- package/lib/runtime/static-files.js +266 -0
- package/lib/runtime/static-files.test.d.ts +1 -0
- package/lib/runtime/static-files.test.js +118 -0
- package/lib/runtime/util.d.ts +28 -0
- package/lib/runtime/util.js +79 -0
- package/lib/utils/base-path.d.ts +106 -13
- package/lib/utils/base-path.js +254 -41
- package/lib/utils/base-path.test.js +219 -51
- package/lib/utils/get-architecture.d.ts +7 -8
- package/lib/utils/get-architecture.js +12 -13
- package/lib/utils/zip-directory.d.ts +14 -0
- package/lib/utils/zip-directory.js +121 -0
- package/lib/utils/zip-directory.test.d.ts +1 -0
- package/lib/utils/zip-directory.test.js +99 -0
- package/package.json +22 -3
- package/scripts/capture-adapter-fixture.mjs +325 -0
- package/scripts/e2e-deploy.sh +398 -0
- package/scripts/e2e-harness/README.md +707 -0
- package/scripts/e2e-harness/app.js +370 -0
- package/scripts/e2e-harness/common.sh +249 -0
- package/scripts/e2e-harness/screen.mjs +302 -0
- package/scripts/e2e-harness/stage-proxy.mjs +145 -0
- package/scripts/e2e-harness/type-filters.mjs +47 -0
- package/scripts/e2e-logs.sh +75 -0
- package/scripts/e2e-offline.sh +91 -0
- package/scripts/e2e-sweep.sh +370 -0
- package/scripts/e2e-warm.sh +114 -0
- package/scripts/zero-config-build.mjs +418 -0
- package/docs/1k-concurrent-users-executions.png +0 -0
- package/docs/plans/adapter-runtime-release.md +0 -362
- package/docs/plans/phase-0-image-function-opt-in.md +0 -295
- package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
- package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
- package/lib/image-optimization/handler-utils.d.ts +0 -34
- package/lib/image-optimization/handler-utils.js +0 -83
- package/lib/image-optimization/handler-utils.test.js +0 -178
- package/lib/nextjs-build/functions.Dockerfile +0 -31
- package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
- package/lib/nextjs-compute/nextjs-image-function.js +0 -59
- package/lib/utils/experimental-flags.d.ts +0 -24
- package/lib/utils/experimental-flags.js +0 -30
- /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
package/docs/breaking-changes.md
CHANGED
|
@@ -1,5 +1,665 @@
|
|
|
1
1
|
# Breaking Changes
|
|
2
2
|
|
|
3
|
+
## 0.7.0 (unreleased)
|
|
4
|
+
|
|
5
|
+
### Requests are served through the adapter runtime, not `next start`
|
|
6
|
+
|
|
7
|
+
cdk-nextjs no longer sets `output: "standalone"`, and no deployment runs the
|
|
8
|
+
`server.js` that standalone generates. Instead, `next build` reports every route
|
|
9
|
+
it built through the [Deployment Adapter API](https://nextjs.org/docs/app/api-reference/adapters/runtime-integration),
|
|
10
|
+
cdk-nextjs stages those outputs and their traced dependencies into
|
|
11
|
+
`.next/cdk-nextjs-adapter/`, and its own server invokes the built entrypoints
|
|
12
|
+
in-process.
|
|
13
|
+
|
|
14
|
+
Nothing in the construct API changes for the common case: the four root
|
|
15
|
+
constructs take the same props, and `adapterPath` in `next.config` — already
|
|
16
|
+
required before this — keeps working. It is now optional, since cdk-nextjs sets
|
|
17
|
+
`NEXT_ADAPTER_PATH` on the build it runs itself; an explicit `adapterPath` still
|
|
18
|
+
wins, because Next.js reads the variable only as that option's default. You still
|
|
19
|
+
need it when cdk-nextjs is not running your build, i.e. `skipBuild: true`. What
|
|
20
|
+
changes:
|
|
21
|
+
|
|
22
|
+
- **Next.js 16.3 or higher is required** (was 16.2). The build reads adapter
|
|
23
|
+
outputs 16.3 added (`routing.middlewareMatchers`, `assetsHashes`), and the
|
|
24
|
+
runtime bundles `@next/routing` 16.3.5. `next build` on an older version now
|
|
25
|
+
fails at once with a message naming the version.
|
|
26
|
+
- **If you set `output: "standalone"` yourself, remove it.** Standalone and the
|
|
27
|
+
adapter are alternatives, not layers — `next build` says so, and a future
|
|
28
|
+
Next.js release may reject the combination outright.
|
|
29
|
+
- **If you have a custom Dockerfile**, it can no longer `COPY .next/standalone`
|
|
30
|
+
or `CMD ["node", "server.js"]`. Copy `.next/cdk-nextjs-adapter/app` to the
|
|
31
|
+
image root and run `node cdk-nextjs-runtime/server.mjs`. Compare against
|
|
32
|
+
`src/nextjs-build/global-containers.Dockerfile`. cdk-nextjs now **rewrites**
|
|
33
|
+
any Dockerfile whose first line is `# ~~ Generated by cdk-nextjs ~~`, so
|
|
34
|
+
upgrades no longer leave a stale one behind (the previous copy is kept as
|
|
35
|
+
`<name>.bak`); delete that line to take ownership of the file. The build arg was renamed too:
|
|
36
|
+
`RELATIVE_PATH_TO_PACKAGE` is now `RELATIVE_PROJECT_DIR` (`"."` for an app at
|
|
37
|
+
the repo root), and only `NextjsRegionalContainers` passes it; the Global
|
|
38
|
+
Containers image no longer needs it. A Dockerfile still reading the old name gets it empty, and in a
|
|
39
|
+
monorepo copies `.next/static` and `public` to the image root instead of the
|
|
40
|
+
app's directory.
|
|
41
|
+
- **Monorepo detection changed mechanism.** It used to find `server.js` with a
|
|
42
|
+
`.next` sibling inside `.next/standalone/`. It now uses the `repoRoot` and
|
|
43
|
+
project directory the adapter reports. No prop to change — this only matters if
|
|
44
|
+
you were relying on the old layout.
|
|
45
|
+
- **`.env` and `.env.production` are staged and loaded explicitly.**
|
|
46
|
+
`writeStandaloneDirectory` used to copy them and `next start` loaded them; the
|
|
47
|
+
adapter hook has neither, so cdk-nextjs copies them into the package and the
|
|
48
|
+
runtime loads them at startup with Next.js's own `loadEnvConfig`. Same result:
|
|
49
|
+
a variable set on the function or task still wins over the files. If you were
|
|
50
|
+
depending on some _other_ env file reaching the server because standalone
|
|
51
|
+
happened to copy it, it did not — only those two were ever copied.
|
|
52
|
+
- **The edge runtime fails the build.** That includes a `middleware.ts` with no
|
|
53
|
+
`export const config = { runtime: "nodejs" }`, since Next.js defaults
|
|
54
|
+
`middleware.ts` to edge, and any route with `export const runtime = "edge"`.
|
|
55
|
+
Rename middleware to `proxy.ts` (Node.js by default) or set
|
|
56
|
+
`runtime: "nodejs"`, and remove `runtime = "edge"` from routes.
|
|
57
|
+
- **Pages API routes are not ended for you.** A route that returns without
|
|
58
|
+
calling `res.end()`, `res.json()` or `res.send()` now stalls until the
|
|
59
|
+
function or ALB timeout, as it does under `next start`. In exchange, a route
|
|
60
|
+
that finishes later — `stream.pipe(res)`, an `externalResolver` proxy, a
|
|
61
|
+
callback-style `res.json` — is no longer cut off with an empty 200.
|
|
62
|
+
- **Request headers Next.js treats as internal are stripped** from viewer
|
|
63
|
+
requests, as `next start` does: `next-resume`, `x-matched-path`,
|
|
64
|
+
`x-nextjs-data`, `x-middleware-*`, `x-now-route-matches` and the rest of Next's
|
|
65
|
+
list. Nothing a browser sends is affected; a client that set one of them to
|
|
66
|
+
steer rendering no longer can.
|
|
67
|
+
- **`next build` must run from the Next.js project directory.** A `buildCommand`
|
|
68
|
+
such as `next build apps/web` run from the repo root now fails the build with a
|
|
69
|
+
message saying so. Use `cd apps/web && next build`, or a package-manager filter
|
|
70
|
+
that runs in the package directory (`pnpm --filter <app> build`).
|
|
71
|
+
|
|
72
|
+
### Functions are zip Lambdas, not container-image Lambdas
|
|
73
|
+
|
|
74
|
+
Both Functions types (`NextjsGlobalFunctions`, `NextjsRegionalFunctions`) now
|
|
75
|
+
package the staged tree as a zip asset. Docker is no longer needed to deploy
|
|
76
|
+
them — only the Containers types still build images.
|
|
77
|
+
|
|
78
|
+
- **`overrides.nextjsFunctions.dockerImageFunctionProps` →
|
|
79
|
+
`overrides.nextjsFunctions.functionProps`.** The keys that were specific to
|
|
80
|
+
container images (`assetImageCodeProps`, and anything under
|
|
81
|
+
`DockerImageFunctionProps` with no `FunctionProps` equivalent) are gone; the
|
|
82
|
+
rest — `memorySize`, `timeout`, `environment`, `vpc`, `logGroup` — move across
|
|
83
|
+
unchanged.
|
|
84
|
+
- **The function is replaced on upgrade.** Its logical ID is unchanged, but
|
|
85
|
+
its package type goes from Image to Zip, which CloudFormation can only do by
|
|
86
|
+
creating a new function and deleting the old one. With a custom
|
|
87
|
+
`functionProps.functionName`, the first deploy fails ("cannot update a stack
|
|
88
|
+
when a custom-named resource requires replacing") and rolls back. For that
|
|
89
|
+
deploy, set a new name (e.g. `my-app-server-v2`) or remove it. To get the
|
|
90
|
+
original name back afterwards, deploy again with it: that is a second
|
|
91
|
+
replacement, which works now the name is free. On `NextjsGlobalFunctions` the
|
|
92
|
+
Function URL is replaced with it, and the distribution follows. Its log group
|
|
93
|
+
is replaced too, named after the new function; the old one is retained
|
|
94
|
+
(`UpdateReplacePolicy: Retain`), so server logs from before the upgrade stay in
|
|
95
|
+
`/aws/lambda/<old function name>`.
|
|
96
|
+
- `NextjsFunctions.function` is a `lambda.Function`, not a
|
|
97
|
+
`DockerImageFunction`.
|
|
98
|
+
- `OptionalDockerImageFunctionProps` is no longer exported.
|
|
99
|
+
- **250 MB unzipped limit.** Zip Lambdas are capped where container images were
|
|
100
|
+
not. cdk-nextjs fails at synth with the group's measured size if a function
|
|
101
|
+
exceeds it; the fix is the new `functionGroups` prop (below).
|
|
102
|
+
- **`functionProps.architecture` is honored.** The Functions types still
|
|
103
|
+
default to the architecture of the machine running synth, as in 0.6.x, so any
|
|
104
|
+
native dependency `next build` traced from it runs as built. Setting
|
|
105
|
+
`overrides.nextjsFunctions.functionProps.architecture` now deploys that
|
|
106
|
+
architecture, with `sharp` staged for it. It is one architecture per
|
|
107
|
+
deployment: a function group's own `overrides.functionProps.architecture`
|
|
108
|
+
that differs is a synth error. An x86 CI runner can deploy arm64 functions. Only
|
|
109
|
+
`sharp` is staged for the target. Any other native dependency in your app is
|
|
110
|
+
still traced from the build machine, so build on the architecture you deploy
|
|
111
|
+
if you have one.
|
|
112
|
+
- **The post-deploy Lambda is always arm64.** It has no native dependencies,
|
|
113
|
+
so it no longer follows the synth machine. The first deploy after upgrading
|
|
114
|
+
from an x86 machine updates it in place.
|
|
115
|
+
|
|
116
|
+
### The dedicated image optimization Lambda is gone
|
|
117
|
+
|
|
118
|
+
`_next/image` is served by the same function as every other route, through
|
|
119
|
+
cdk-nextjs's own S3-aware optimizer, after middleware. The separate Lambda that
|
|
120
|
+
briefly existed behind an env var is removed along with it:
|
|
121
|
+
|
|
122
|
+
- `CDK_NEXTJS_EXPERIMENTAL_DEDICATED_IMAGE_FUNCTION` — **removed.** It was never
|
|
123
|
+
a supported prop; unset it in CI and anywhere else it was exported. It is now
|
|
124
|
+
ignored, not honored.
|
|
125
|
+
- `NextjsImageFunction` construct, `NextjsImageFunctionProps`,
|
|
126
|
+
`NextjsImageFunctionOverrides`,
|
|
127
|
+
`NextjsGlobalFunctions.nextjsImageFunction`,
|
|
128
|
+
`NextjsRegionalFunctions.nextjsImageFunction` — removed.
|
|
129
|
+
- `NextjsDistributionProps.imageFunctionUrl`, `NextjsApiProps.imageFunction`,
|
|
130
|
+
`imageIntegrationProps` — removed.
|
|
131
|
+
- `overrides.nextjsImageFunctionProps` — removed.
|
|
132
|
+
- `overrides.nextjsImageFunction` on `NextjsGlobalFunctions` and
|
|
133
|
+
`NextjsRegionalFunctions`, and the protected
|
|
134
|
+
`NextjsBaseConstruct.createNextjsImageFunction()` a subclass could override —
|
|
135
|
+
removed. Setting the key is now a compile error; delete it, and size image
|
|
136
|
+
requests through `overrides.nextjsFunctions` as below.
|
|
137
|
+
- `NextjsDistributionOverrides.imageFunctionUrlOriginWithOACProps` — removed;
|
|
138
|
+
there is no image function origin any more.
|
|
139
|
+
- `NextjsBuild.imageOptimizationAssetPath` — removed.
|
|
140
|
+
|
|
141
|
+
Independent memory and timeout sizing for image requests is the cost. Raise
|
|
142
|
+
`overrides.nextjsFunctions.functionProps.memorySize` if image latency regresses.
|
|
143
|
+
|
|
144
|
+
### `healthCheckPath` moved to the two Containers constructs
|
|
145
|
+
|
|
146
|
+
It was required on all four root constructs, but only `NextjsGlobalContainers`
|
|
147
|
+
and `NextjsRegionalContainers` ever read it — for the ALB target group and the
|
|
148
|
+
ECS container health check. The Functions types took it and ignored it: Lambda
|
|
149
|
+
has no long-lived process to probe, so there was nothing for it to do there.
|
|
150
|
+
|
|
151
|
+
- `NextjsGlobalFunctions` / `NextjsRegionalFunctions`: the prop no longer exists.
|
|
152
|
+
**Remove it** — leaving it in place is now a type error rather than a no-op.
|
|
153
|
+
The `/api/health` route in your app is only needed if something else calls it.
|
|
154
|
+
- `NextjsGlobalContainers` / `NextjsRegionalContainers`: unchanged, still
|
|
155
|
+
required, and still prefixed with your app's `basePath` (0.6.2) before it
|
|
156
|
+
reaches the target group and the container probe. Those two are now its only
|
|
157
|
+
consumers — the Lambda Web Adapter readiness check it also fed in 0.6.x is gone
|
|
158
|
+
along with LWA itself.
|
|
159
|
+
- `NextjsComputeBaseProps.healthCheckPath` moved to `NextjsContainersProps`.
|
|
160
|
+
Deployed resources are identical either way; this only changes which props
|
|
161
|
+
compile.
|
|
162
|
+
|
|
163
|
+
### `NextjsRegionalFunctions` puts the API Gateway stage back itself
|
|
164
|
+
|
|
165
|
+
API Gateway strips the stage (`/prod`) from the path it passes to Lambda, so an
|
|
166
|
+
app built with `basePath: "/prod"` — the setup `examples/regional-functions`
|
|
167
|
+
documents — used to 404 every request unless middleware prepended the stage
|
|
168
|
+
again. The example shipped that middleware in `examples/app-playground/proxy.ts`,
|
|
169
|
+
driven by `PREPEND_APIGW_STAGE` and `API_GATEWAY_STAGE` on the function.
|
|
170
|
+
|
|
171
|
+
The Lambda shell now does it: when the app's `basePath` starts with the prefix
|
|
172
|
+
API Gateway stripped, Next.js is handed the request's unstripped path
|
|
173
|
+
(`requestContext.path`). The stage is read off each request, so nothing is
|
|
174
|
+
configured and a renamed stage just works. An app without a `basePath`, or behind
|
|
175
|
+
a custom domain mapped at the root, sees exactly what it saw before.
|
|
176
|
+
|
|
177
|
+
- **If you copied the stage-prepending middleware, remove it** along with the two
|
|
178
|
+
environment variables. The copy in the example skipped paths already starting
|
|
179
|
+
with the stage, so it is inert rather than harmful — but a variant without that
|
|
180
|
+
guard now rewrites `/prod/foo` to `/prod/prod/foo` and 404s.
|
|
181
|
+
- **Redirects keep the stage.** A trailing-slash or repeated-slash redirect used
|
|
182
|
+
to answer with a `Location` outside the stage (`/isr/1` rather than
|
|
183
|
+
`/prod/isr/1`), which API Gateway then refused with a 403. They now match
|
|
184
|
+
`next start`.
|
|
185
|
+
- **`/prod/` redirects to `/prod`**, as it does under `next start` for any app
|
|
186
|
+
with `basePath: "/prod"`. The middleware used to answer it directly with 200.
|
|
187
|
+
One extra hop on the stage root, and a page-relative URL resolved from the app's
|
|
188
|
+
root now resolves against `/prod` rather than `/prod/`.
|
|
189
|
+
- **The `basePath` prop is now derived when unset**: the app's `basePath` minus
|
|
190
|
+
the prefix API Gateway strips (the stage, or a custom domain's base path
|
|
191
|
+
mapping from `restApiProps.domainName`). `basePath: "/prod"` still mounts at
|
|
192
|
+
the root, so the common setup is unchanged. An app whose `basePath` API Gateway
|
|
193
|
+
does not strip (`"/docs"` behind a root-mapped custom domain) now gets its
|
|
194
|
+
resources and its static assets' S3 keys under `docs`. Before, both stayed at
|
|
195
|
+
the root and every bundle 404'd. An explicit prop still wins. A domain
|
|
196
|
+
attached with `addDomainName()` is invisible at synth, so set the prop in that
|
|
197
|
+
case; `basePath: "/"` mounts at the root, for a domain whose base path mapping
|
|
198
|
+
strips the app's whole `basePath`. A `stageName` set through
|
|
199
|
+
`overrides.nextjsApi.restApiProps.deployOptions` is honored when deriving.
|
|
200
|
+
|
|
201
|
+
### Lower-level constructs: new and renamed props
|
|
202
|
+
|
|
203
|
+
The four root constructs fill these in; only code that uses `NextjsFunctions`,
|
|
204
|
+
`NextjsContainers` or `NextjsBuild` directly has to change.
|
|
205
|
+
|
|
206
|
+
- **`NextjsComputeBaseProps`** (the `NextjsFunctions` / `NextjsContainers`
|
|
207
|
+
props) now requires `staticAssetsBucket`, and takes an optional
|
|
208
|
+
`staticAssetsKeyPrefix`; take both from `NextjsStaticAssets` (`bucket`,
|
|
209
|
+
`keyPrefix`). `relativePathToPackage` is removed, and `healthCheckPath` moved
|
|
210
|
+
(above).
|
|
211
|
+
- **`NextjsComputeBaseProps.buildDirectory` moved to `NextjsContainersProps`.**
|
|
212
|
+
`NextjsFunctions` never read it. Stop passing it when you construct
|
|
213
|
+
`NextjsFunctions` directly; `NextjsContainers` still requires it.
|
|
214
|
+
- **`NextjsFunctionsProps`** now requires `deploymentRoots` and takes an optional
|
|
215
|
+
`architecture`; **`NextjsContainersProps`** now requires `relativeProjectDir`.
|
|
216
|
+
Take them from `NextjsBuild`'s fields of the same names.
|
|
217
|
+
- **`NextjsBuild.relativePathToPackage` → `NextjsBuild.relativeProjectDir`**, now
|
|
218
|
+
read from the adapter manifest. New read-only fields: `architecture`,
|
|
219
|
+
`deploymentRoots`, `functionGroupBehaviors`, `nextConfigAssetPrefix`,
|
|
220
|
+
`nextConfigAssetPrefixPath`.
|
|
221
|
+
- **`NextjsBuild.buildId` ends in `-<deploymentId>`** when the app sets
|
|
222
|
+
`deploymentId` (or `NEXT_DEPLOYMENT_ID`), so it no longer always equals
|
|
223
|
+
`.next/BUILD_ID`.
|
|
224
|
+
- **`NextjsBuild.relativePathToEntrypoint` is `cdk-nextjs-runtime/server.mjs`**,
|
|
225
|
+
not `server.js` (or `<package>/server.js` in a monorepo). Update any task
|
|
226
|
+
definition or command you built from it.
|
|
227
|
+
- **`NextjsBaseConstruct.createNextjsFunctions()`** (protected) takes no
|
|
228
|
+
parameter; it reads `overrides.nextjsFunctions` itself. A subclass that passed
|
|
229
|
+
overrides to it should set them there instead.
|
|
230
|
+
|
|
231
|
+
### `nextjsFunctionsProps` is removed
|
|
232
|
+
|
|
233
|
+
`overrides.nextjsGlobalFunctions.nextjsFunctionsProps` and
|
|
234
|
+
`overrides.nextjsRegionalFunctions.nextjsFunctionsProps` are gone, along with
|
|
235
|
+
the `NextjsFunctionsConstructOverrides` interface that declared them. Every
|
|
236
|
+
`NextjsFunctionsProps` value is now either wired by the root construct from its
|
|
237
|
+
siblings (the cache, the static assets, the build) or set elsewhere, and
|
|
238
|
+
setting one there only desynced the stack: a different `staticAssetsKeyPrefix`,
|
|
239
|
+
for example, made the functions read a prefix nothing uploaded to.
|
|
240
|
+
|
|
241
|
+
- **Migration:** move `nextjsFunctionsProps.overrides` to
|
|
242
|
+
`overrides.nextjsFunctions`. Set `functionGroups` on the root construct's
|
|
243
|
+
props, and the architecture through
|
|
244
|
+
`overrides.nextjsFunctions.functionProps.architecture`. Drop any other key.
|
|
245
|
+
|
|
246
|
+
### Fix: a VPC passed to the ECS cluster through `overrides` is kept
|
|
247
|
+
|
|
248
|
+
On `NextjsGlobalContainers` and `NextjsRegionalContainers`, a VPC passed through
|
|
249
|
+
`overrides.nextjsContainers.ecsClusterProps.vpc` was overwritten when the
|
|
250
|
+
top-level `vpc` prop was unset, so the cluster created its own VPC. The override
|
|
251
|
+
is now used. If you set it, the next deploy moves the tasks into that VPC and
|
|
252
|
+
deletes the one the cluster created.
|
|
253
|
+
|
|
254
|
+
### Fix: `NextjsGlobalFunctions` honors the `distribution` prop
|
|
255
|
+
|
|
256
|
+
0.6.x silently ignored `distribution` on `NextjsGlobalFunctions` and always
|
|
257
|
+
created its own (`NextjsGlobalContainers` already honored it). If you set it,
|
|
258
|
+
the next deploy deletes the construct-created distribution, and with it its
|
|
259
|
+
`dXXXX.cloudfront.net` domain, and adds the app's behaviors to yours instead.
|
|
260
|
+
Without a `basePath` no catch-all behavior is added, so point your
|
|
261
|
+
distribution's default behavior at the function, or set `basePath`.
|
|
262
|
+
|
|
263
|
+
### Responses without `Cache-Control` are no longer cached by CloudFront
|
|
264
|
+
|
|
265
|
+
The dynamic cache policy on `NextjsGlobalFunctions` and `NextjsGlobalContainers`
|
|
266
|
+
now has a default TTL of 0 rather than CDK's default of one day. Before, any
|
|
267
|
+
dynamic response that sent no `Cache-Control` - typically a route handler - was
|
|
268
|
+
cached at the edge for 24 hours (per query string and cookie set). Next.js treats
|
|
269
|
+
"no header" as "not cacheable", and so does every other host an app is likely to
|
|
270
|
+
have been written against.
|
|
271
|
+
|
|
272
|
+
What Next.js means to cache is unaffected: ISR, SSG and PPR shells send
|
|
273
|
+
`s-maxage`, which the policy still honors up to its one-year `maxTtl`. If you
|
|
274
|
+
relied on the old behavior, send `Cache-Control: s-maxage=<seconds>` from the
|
|
275
|
+
route, or restore it with
|
|
276
|
+
`overrides.nextjsDistribution.dynamicCachePolicyProps.defaultTtl`.
|
|
277
|
+
|
|
278
|
+
An override of `dynamicCachePolicyProps.maxTtl` below a day was silently raised
|
|
279
|
+
to a day before (CDK lifts `maxTtl` to `defaultTtl`), and is now honored as
|
|
280
|
+
written. In particular `maxTtl: Duration.seconds(0)` now really turns the dynamic
|
|
281
|
+
cache off, and the policy drops its cache key to match, because CloudFront
|
|
282
|
+
rejects a policy that caches nothing but keys on headers, cookies or query
|
|
283
|
+
strings. What reaches the origin does not change: the origin request policy
|
|
284
|
+
forwards all of those regardless.
|
|
285
|
+
|
|
286
|
+
### Behavior change: the dynamic cache key no longer includes `x-matched-path` or `x-next-cache-tags`
|
|
287
|
+
|
|
288
|
+
The runtime strips `x-matched-path` from viewer requests, and viewers never send
|
|
289
|
+
`x-next-cache-tags`, so both only took 2 of the policy's 10 cache-key header
|
|
290
|
+
slots and let clients fragment the edge cache. The cache key changes, so expect
|
|
291
|
+
one round of CloudFront cache misses on dynamic routes after upgrading. No
|
|
292
|
+
action needed.
|
|
293
|
+
|
|
294
|
+
### Behavior change: the deploy-time invalidation is scoped to `basePath`
|
|
295
|
+
|
|
296
|
+
With a `basePath`, the CloudFront invalidation each deploy creates now covers
|
|
297
|
+
only the app's URIs (`/base`, `/base?*`, `/base/*`) instead of `/*`, so
|
|
298
|
+
deploying one app no longer empties the edge cache of other apps on a shared
|
|
299
|
+
distribution. Without a `basePath` it is still `/*`.
|
|
300
|
+
`overrides.nextjsPostDeploy.customResourceProperties.createInvalidationCommandInput`
|
|
301
|
+
still replaces it.
|
|
302
|
+
|
|
303
|
+
### Behavior change: `public/` follows `next start`
|
|
304
|
+
|
|
305
|
+
The runtime now serves `public/` the way `next start` does. A `public/` file
|
|
306
|
+
wins over an app route at the same path (`public/robots.txt` over
|
|
307
|
+
`app/robots.ts`), and only GET and HEAD are answered; other methods get a 405.
|
|
308
|
+
Rewrites onto a `public/` file (`rewrites()`, or a middleware rewrite to
|
|
309
|
+
`/maintenance.html`) serve it on every type, as they did on 0.6.x:
|
|
310
|
+
|
|
311
|
+
- **`NextjsRegionalContainers`** copies `public/` and `.next/static` into the
|
|
312
|
+
image, since nothing in front of it answers those paths, and lists `public/`
|
|
313
|
+
when the task starts, so files a `postbuild` step writes (`next-sitemap`'s
|
|
314
|
+
`sitemap.xml`, for one) are served.
|
|
315
|
+
- **Every other type** doesn't carry `public/`. cdk-nextjs lists it at synth,
|
|
316
|
+
after the build command (so `postbuild` output is included), and the runtime
|
|
317
|
+
streams a rewritten file from the static assets bucket. A file's own URL is
|
|
318
|
+
still answered by S3 at the edge. A rewritten file keeps the `Cache-Control`
|
|
319
|
+
its S3 object carries, and `Range` requests are honored.
|
|
320
|
+
|
|
321
|
+
On `NextjsGlobalFunctions` and `NextjsGlobalContainers`, a top-level `public/`
|
|
322
|
+
entry whose name has no ASCII letter, digit or other character CloudFront can
|
|
323
|
+
match (`public/фото/`) no longer gets a cache behavior, since that behavior
|
|
324
|
+
would have captured every app route of the same length. The synth warns, and
|
|
325
|
+
the entry's files are served by the server from S3 rather than by the edge.
|
|
326
|
+
Rename it, or move it under an ASCII-named directory, to serve them directly.
|
|
327
|
+
The same goes for a top-level name an API Gateway resource can't express on
|
|
328
|
+
`NextjsRegionalFunctions` (`public/hello e2e.txt`), which used to 404.
|
|
329
|
+
|
|
330
|
+
### New (non-breaking): `functionGroups`
|
|
331
|
+
|
|
332
|
+
Splits one Next.js app across several Lambda functions, one per declared group of
|
|
333
|
+
routes, so an app too large for Lambda's 250 MB unzipped limit can still deploy.
|
|
334
|
+
Opt-in: omit it and you get one function, exactly as before. See
|
|
335
|
+
[README](../README.md#splitting-a-large-app-across-functions).
|
|
336
|
+
|
|
337
|
+
Splitting is checked when `next build` runs: every URL a grouped file serves
|
|
338
|
+
must reach that file's group at the edge, or the build fails naming the URL and
|
|
339
|
+
the pattern to add. That rejects, among others, a pattern that claims only some
|
|
340
|
+
of the URLs one file serves (`/en` for an `app/[locale]/page.tsx` that also
|
|
341
|
+
serves `/de`), a static rewrite whose source and destination land in different
|
|
342
|
+
groups, and a group pattern that duplicates or is shadowed by a `public/`
|
|
343
|
+
behavior. An optional catch-all's parent (`/blog` for `/blog/[[...slug]]`) is
|
|
344
|
+
routed with `/blog/**` automatically, and listing `/blog` as well is now an
|
|
345
|
+
error. Intercepting routes (`(..)photo`) are packaged with the group that owns
|
|
346
|
+
the URL they intercept. Rewrites made by middleware are not checked.
|
|
347
|
+
|
|
348
|
+
Two things only work within a group, because they run a route in-process in the
|
|
349
|
+
function that received the request. A Pages Router `res.revalidate()` can only
|
|
350
|
+
revalidate pages in its own group (the error names the owning group). And the
|
|
351
|
+
image optimizer (`/_next/image`) always runs in the `default` group, so an
|
|
352
|
+
`<Image>` whose local `src` is served by a route in another group
|
|
353
|
+
(`/api/avatar/42` under `/api/**`) can't be fetched and fails instead of being
|
|
354
|
+
optimized. `public/` and `_next/static` sources are read from S3 and are
|
|
355
|
+
unaffected. Put image-serving routes in `default`, or use a static or remote
|
|
356
|
+
source.
|
|
357
|
+
|
|
358
|
+
Edge path matching is case-sensitive and Next.js's isn't, so `/API/reports/1`
|
|
359
|
+
misses a `/api/reports/**` group and reaches the default function. That
|
|
360
|
+
function answers a 308 to the route's own spelling (`/api/reports/1`, the
|
|
361
|
+
dynamic values' case kept) instead of a 500, or a 404 if the URL isn't a case
|
|
362
|
+
variant of the route.
|
|
363
|
+
|
|
364
|
+
On `NextjsRegionalFunctions`, removing a group (or a top-level `public/` entry)
|
|
365
|
+
used to leave its route in the live API Gateway stage: CloudFormation snapshots
|
|
366
|
+
the stage before it deletes removed resources, so the old route kept pointing at
|
|
367
|
+
the deleted function and answered 500. A small function now redeploys the stage
|
|
368
|
+
when the stack update completes, so the gap is a minute or so after the update
|
|
369
|
+
rather than until the next deploy. Turn it off with
|
|
370
|
+
`overrides.nextjsRegionalFunctions.nextjsApiProps.redeployAfterUpdate: false`
|
|
371
|
+
(`nextjsApiProps` is now the all-optional `OptionalNextjsApiProps`, so it takes
|
|
372
|
+
just that flag).
|
|
373
|
+
The redeploy is triggered by the stack's EventBridge status event, so an
|
|
374
|
+
account bootstrapped with
|
|
375
|
+
[`docs/cdk-nextjs-cfn-exec-policy.json`](./cdk-nextjs-cfn-exec-policy.json)
|
|
376
|
+
needs `events:*` added to its CloudFormation execution policy, or the deploy
|
|
377
|
+
fails creating the rule. The redeploy moves the stage off the deployment
|
|
378
|
+
CloudFormation made, so drift detection reports the stage's `DeploymentId` as
|
|
379
|
+
modified; that is expected.
|
|
380
|
+
|
|
381
|
+
`OptionalNextjsApiProps` omits `overrides` and `functionGroups`, so
|
|
382
|
+
`nextjsApiProps.overrides` no longer compiles. `functionGroups` belongs on the
|
|
383
|
+
root construct's props, where the build checks routes against it, and
|
|
384
|
+
`overrides.nextjsApi` is where `NextjsRegionalFunctions` reads the `RestApi`'s
|
|
385
|
+
props from to derive `basePath`; one set under `nextjsApiProps` used to replace
|
|
386
|
+
it, so the two could disagree about the stage.
|
|
387
|
+
|
|
388
|
+
- **Migration:** move `nextjsApiProps.overrides` to `overrides.nextjsApi`.
|
|
389
|
+
|
|
390
|
+
With groups and Pages Router data routes, the `_next/data` behaviors name the
|
|
391
|
+
literal Next.js build ID, so they change on every deploy unless a
|
|
392
|
+
`deploymentId` pins it.
|
|
393
|
+
|
|
394
|
+
### Behavior change: the cache-behavior limit is 75 and configurable
|
|
395
|
+
|
|
396
|
+
`NextjsDistribution` used to reject a build needing more than 25 cache behaviors
|
|
397
|
+
(`public/` entries and, now, group patterns). The limit is CloudFront's default
|
|
398
|
+
quota of 75, set with the new `maxCacheBehaviors` prop if your account's quota
|
|
399
|
+
was raised. The check counts only the behaviors cdk-nextjs adds: if you pass
|
|
400
|
+
in a distribution, or add behaviors through
|
|
401
|
+
`overrides.nextjsDistribution.distributionProps`, lower `maxCacheBehaviors` by
|
|
402
|
+
the behaviors those already have.
|
|
403
|
+
|
|
404
|
+
### Behavior change: CloudFront's own viewer-request function can't be replaced on Global Functions
|
|
405
|
+
|
|
406
|
+
`NextjsGlobalFunctions` puts a CloudFront Function on viewer-request for the
|
|
407
|
+
dynamic and `_next/image*` behaviors. It overwrites `X-Forwarded-Host` with the
|
|
408
|
+
viewer's `Host`, which the runtime trusts behind the Function URL, and redirects
|
|
409
|
+
repeated slashes. `functionAssociations` in `overrides.dynamicBehaviorOptions`
|
|
410
|
+
or `overrides.imageBehaviorOptions` used to replace it outright, which let a
|
|
411
|
+
viewer's own `X-Forwarded-Host` reach the app (host injection into redirects and
|
|
412
|
+
absolute URLs, cached for other viewers). Now:
|
|
413
|
+
|
|
414
|
+
- associations on other event types (viewer-response, say) are added next to it;
|
|
415
|
+
- an association on viewer-request throws at synth, since CloudFront allows one
|
|
416
|
+
function per event type per behavior. Move that logic to viewer-response or
|
|
417
|
+
into middleware.
|
|
418
|
+
|
|
419
|
+
The runtime trusts `X-Forwarded-Host` only on a request Lambda reports as
|
|
420
|
+
IAM-authenticated, so a Function URL overridden to `authType: NONE` builds its
|
|
421
|
+
URLs from `Host`.
|
|
422
|
+
|
|
423
|
+
The Containers types are unaffected: their origin sees the viewer's `Host`.
|
|
424
|
+
|
|
425
|
+
### Behavior change: Global Containers builds absolute URLs with the viewer's protocol
|
|
426
|
+
|
|
427
|
+
Without a certificate, CloudFront reaches the ALB over plain HTTP, so the ALB's
|
|
428
|
+
`X-Forwarded-Proto` was `http`, and every absolute URL the app built from the
|
|
429
|
+
request - `request.url`, `req.nextUrl.origin`, redirects, the origin a server
|
|
430
|
+
action is forwarded to - came out as `http://` behind viewers on HTTPS.
|
|
431
|
+
`NextjsGlobalContainers` now forwards CloudFront's own headers to the ALB (the
|
|
432
|
+
managed `AllViewerAndCloudFrontHeaders-2022-06` origin request policy, which
|
|
433
|
+
replaces `AllViewer`), and the container reads the viewer's protocol from
|
|
434
|
+
`CloudFront-Forwarded-Proto`. The first deploy after upgrading updates the
|
|
435
|
+
distribution, a CloudFront change of roughly ten minutes. An
|
|
436
|
+
`overrides.nextjsDistribution.dynamicBehaviorOptions.originRequestPolicy` of
|
|
437
|
+
your own still wins; if it does not forward `CloudFront-Forwarded-Proto`, the
|
|
438
|
+
container falls back to `X-Forwarded-Proto` as before.
|
|
439
|
+
|
|
440
|
+
### Behavior change: narrower CloudFront grants
|
|
441
|
+
|
|
442
|
+
- **`NextjsGlobalContainers`** passes the distribution ID to the task as
|
|
443
|
+
`CDK_NEXTJS_DISTRIBUTION_ID`, and its `cloudfront:CreateInvalidation` grant
|
|
444
|
+
names that distribution instead of `distribution/*`. The
|
|
445
|
+
`cdk-nextjs-distribution-id-*` SSM parameter and the task's
|
|
446
|
+
`ssm:GetParameter` grant are gone.
|
|
447
|
+
- **`NextjsGlobalFunctions`**: its `cloudfront:CreateInvalidation` grant also
|
|
448
|
+
names the distribution instead of `distribution/*`. It keeps the SSM
|
|
449
|
+
parameter, since the distribution depends on the function and the function
|
|
450
|
+
can't name it back; both statements moved from each function role's default
|
|
451
|
+
policy into one `InvalidationPolicy` (`AWS::IAM::Policy`) attached to every
|
|
452
|
+
group's role. CloudFront's `lambda:InvokeFunction` permission
|
|
453
|
+
on each function now has the distribution as its `SourceArn`, and moved from
|
|
454
|
+
`NextjsFunctions` to `NextjsDistribution`. Wiring the two by hand, the
|
|
455
|
+
distribution now adds it.
|
|
456
|
+
|
|
457
|
+
### Behavior change: a missing object on the static S3 origin is a 404, not a 403
|
|
458
|
+
|
|
459
|
+
The bucket policy now grants CloudFront's Origin Access Control principal
|
|
460
|
+
`s3:ListBucket` on the static-assets bucket as well as `s3:GetObject`, so S3
|
|
461
|
+
answers a missing `_next/static` or `public/` object with a 404 instead of a 403. Nothing is listable through the distribution: CloudFront only ever asks for
|
|
462
|
+
one key. If you configured `errorResponses` (or monitoring) for 403 from the
|
|
463
|
+
static behaviors, change them to 404.
|
|
464
|
+
|
|
465
|
+
### Behavior change: a missing `_next/static` file is a plain-text 404
|
|
466
|
+
|
|
467
|
+
A request for a `/_next/static/` file that doesn't exist - typically a client
|
|
468
|
+
holding chunk hashes from the previous deploy - and a request for a missing
|
|
469
|
+
image, script, font or style (by `Sec-Fetch-Dest`) now get a plain-text
|
|
470
|
+
`Not Found` with `Cache-Control: no-store`, as `next start` answers them, instead
|
|
471
|
+
of rendering your `not-found` page.
|
|
472
|
+
|
|
473
|
+
### New: `'use cache: remote'` is shared across instances
|
|
474
|
+
|
|
475
|
+
The adapter now also sets Next.js's
|
|
476
|
+
[`cacheHandlers`](https://nextjs.org/docs/app/api-reference/config/next-config-js/cacheHandlers):
|
|
477
|
+
`remote` stores `'use cache: remote'` entries in the cache bucket (under
|
|
478
|
+
`<buildId>/_use-cache/`, with an in-memory tier in front), so every Lambda
|
|
479
|
+
instance or Fargate task serves the same entry. Before, Next.js fell back to its
|
|
480
|
+
per-process in-memory handler, and `'use cache: remote'` was no more shared than
|
|
481
|
+
`'use cache'`.
|
|
482
|
+
|
|
483
|
+
`default` keeps plain `'use cache'` in memory, as before, but its tags now go
|
|
484
|
+
through the revalidation table: a `revalidateTag`, `updateTag` or
|
|
485
|
+
`revalidatePath` expires `'use cache'` entries on every instance within
|
|
486
|
+
`CDK_NEXTJS_TAG_REFRESH_MS` (1 second by default), instead of only on
|
|
487
|
+
the instance that ran it.
|
|
488
|
+
|
|
489
|
+
A `cacheHandlers.default` or `cacheHandlers.remote` your `next.config` sets is
|
|
490
|
+
left alone. See [README](../README.md#use-cache-and-use-cache-remote) for the
|
|
491
|
+
cost and the settings.
|
|
492
|
+
|
|
493
|
+
If you register the adapter yourself and copy its files rather than installing
|
|
494
|
+
the package (as the examples' `sync-cdk-nextjs` script does), copy
|
|
495
|
+
`lib/adapter/use-cache-default-handler.mjs` and
|
|
496
|
+
`lib/adapter/use-cache-remote-handler.mjs` too: the adapter resolves them through
|
|
497
|
+
the package's `cdk-nextjs/cache-handlers/default` and `/remote` exports.
|
|
498
|
+
|
|
499
|
+
### Behavior change: the revalidation table gains a TTL and a log
|
|
500
|
+
|
|
501
|
+
Instances no longer re-read every tag marker they keep once a second, for
|
|
502
|
+
`'use cache'`/`'use cache: remote'` or for ISR and the data cache. With up to
|
|
503
|
+
1000 kept tags that was ten `BatchGetItem`s a second per instance, all on one
|
|
504
|
+
DynamoDB partition, so a handful of busy instances could throttle it (and each
|
|
505
|
+
cost about 500 RCU a second).
|
|
506
|
+
|
|
507
|
+
Instead, each `revalidateTag`/`updateTag` also writes a row to a revalidation
|
|
508
|
+
log (`pk = <buildId>#log`, `sk = <epoch-ms>#<tag>`), and each instance sends one
|
|
509
|
+
`Query` per `CDK_NEXTJS_TAG_REFRESH_MS` for the rows it hasn't seen. ISR, the
|
|
510
|
+
data cache and `'use cache'` share one copy of the markers per instance, so one
|
|
511
|
+
query serves them all. `0` queries the log on every check. The marker rows stay the source of truth: an instance still reads a tag's
|
|
512
|
+
marker the first time it needs it, and re-reads each one it keeps every 7.5
|
|
513
|
+
to 10 minutes, at most 100 a second. After a gap the log may not cover, it forgets
|
|
514
|
+
them and reads each again when it's next needed.
|
|
515
|
+
|
|
516
|
+
- An instance now keeps up to 10,000 tags' markers, up from 1,000 for
|
|
517
|
+
`'use cache'`. Every path is a tag of its own (`_N_T_/<path>`), so an app with
|
|
518
|
+
1,000 tagged pages needs 2,000, and at 1,000 it kept evicting and re-reading
|
|
519
|
+
them.
|
|
520
|
+
|
|
521
|
+
- The table `NextjsCache` creates now has TTL on the `ttl` attribute, which the
|
|
522
|
+
log rows set 15 minutes out. Enabling it is an in-place update.
|
|
523
|
+
`revalidationTableProps` in `overrides` still wins.
|
|
524
|
+
- If you pass your own `revalidationTable`, enable TTL on `ttl` yourself, or
|
|
525
|
+
the log rows accumulate.
|
|
526
|
+
- `revalidateTag` costs one more write per tag (the log row's `PutItem`),
|
|
527
|
+
which the existing table grant already allows.
|
|
528
|
+
- For ISR and the data cache, a marker read that fails is retried on the next
|
|
529
|
+
refresh (up to `CDK_NEXTJS_TAG_REFRESH_MS` later) rather than on the very
|
|
530
|
+
next check. The entry is treated as valid in between, as before.
|
|
531
|
+
|
|
532
|
+
### Sharing a `cacheBucket` or `revalidationTable` between deployments is not supported
|
|
533
|
+
|
|
534
|
+
Earlier docs said several deployments (branches, stages, apps) could safely
|
|
535
|
+
share one `cacheBucket` and one `revalidationTable` because entries are keyed
|
|
536
|
+
by `buildId`. They can't, and couldn't in earlier versions either: every
|
|
537
|
+
deploy's post-deploy step deletes every cache object under a `<buildId>/`
|
|
538
|
+
prefix other than its own, and the revalidation entries of the build it last
|
|
539
|
+
recorded in the table's `METADATA` row, which with a shared table is whichever
|
|
540
|
+
deployment deployed last. So deploying one deployment wiped the others' caches.
|
|
541
|
+
The docs now say what the code does: bring-your-own `cacheBucket` and
|
|
542
|
+
`revalidationTable` are still supported, but each must be dedicated to one
|
|
543
|
+
deployment.
|
|
544
|
+
|
|
545
|
+
`staticAssetsBucket` can still be shared between deployments with different
|
|
546
|
+
`basePath`s (different S3 key prefixes), since pruning is scoped to
|
|
547
|
+
`<basePath>/_next/`. Two deployments under the same prefix, such as subdomain
|
|
548
|
+
previews all served at the root, overwrite each other's `public/` files and
|
|
549
|
+
prune each other's `_next/` assets once they are past the prune TTL (30 days by
|
|
550
|
+
default), so give those their own buckets too.
|
|
551
|
+
|
|
552
|
+
- **Migration:** if deployments share a cache bucket or revalidation table, give
|
|
553
|
+
each its own. Either remove the `cacheBucket`/`revalidationTable` props and let
|
|
554
|
+
cdk-nextjs create them in each stack (removed with the stack), or create a
|
|
555
|
+
dedicated bucket (and a table with `pk`/`sk` String keys and TTL on `ttl`) per
|
|
556
|
+
deployment and point that deployment's props at it. Nothing needs copying: the
|
|
557
|
+
cache is re-seeded from the build on the next deploy. Delete the old shared
|
|
558
|
+
bucket and table once nothing points at them.
|
|
559
|
+
[examples/bring-your-own](../examples/bring-your-own) now shares only the VPC,
|
|
560
|
+
ECS cluster, and ALB between branches.
|
|
561
|
+
- **Upgrading bring-your-own:** deploy every branch stack first, then
|
|
562
|
+
`SharedInfra`. The new `SharedInfra` deletes the shared cache bucket, static
|
|
563
|
+
assets bucket, revalidation table and their SSM parameters, which a branch
|
|
564
|
+
stack still on the old version serves from and reads at deploy; deployed
|
|
565
|
+
first, each branch has moved onto its own buckets and table before they go.
|
|
566
|
+
|
|
567
|
+
### Performance compared with 0.6.2
|
|
568
|
+
|
|
569
|
+
Measured with the [load tests](../examples/load-tests) against
|
|
570
|
+
[`examples/bench-app`](../examples/bench-app), both versions deployed side by
|
|
571
|
+
side from one EC2 load generator per stack in us-east-1: 2048 MB Lambda
|
|
572
|
+
functions, and 1 vCPU / 2 GB Fargate tasks autoscaling from 2 to 10. Latency is
|
|
573
|
+
p50 / p99 in ms; "faster" is 0.6.2 over 0.7.0.
|
|
574
|
+
|
|
575
|
+
| Construct | Compute p50 | Compute p99 | Cold start p50 | Compared at |
|
|
576
|
+
| -------------------------- | ----------- | ----------- | -------------- | ---------------- |
|
|
577
|
+
| `NextjsGlobalFunctions` | 1.7× faster | 1.5× faster | 1.3× faster | 1000 req/s/route |
|
|
578
|
+
| `NextjsGlobalContainers` | 1.1× faster | 1.1× faster | – | 10 req/s/route |
|
|
579
|
+
| `NextjsRegionalContainers` | 7.0× faster | 3.9× faster | – | 10 req/s/route |
|
|
580
|
+
| `NextjsRegionalFunctions` | 1.9× faster | 1.5× faster | 1.6× faster | 1000 req/s/route |
|
|
581
|
+
|
|
582
|
+
Compute is the geometric mean over the routes that reach compute on every
|
|
583
|
+
construct (`ssr`, `stream`, `rsc`, `api`), at the highest rate both versions
|
|
584
|
+
served with under 1% errors. `stream` counts by time to first byte, since its
|
|
585
|
+
total includes a fixed 200 ms delay in the page.
|
|
586
|
+
|
|
587
|
+
The Containers constructs are compared at 10 req/s per route because 50 was
|
|
588
|
+
past capacity for 0.6.2 on `NextjsGlobalContainers` (5% errors) and for both
|
|
589
|
+
versions on `NextjsRegionalContainers`. A step lasts 3 minutes, less than the
|
|
590
|
+
time a new task takes to start serving, so each run measures the two tasks it
|
|
591
|
+
started with. On `NextjsGlobalContainers`, 0.7.0 is also 1.1× faster at 50
|
|
592
|
+
req/s per route.
|
|
593
|
+
|
|
594
|
+
**`NextjsGlobalFunctions`**: RSC payloads and route handlers are the big
|
|
595
|
+
change, since they no longer pass through the Lambda Web Adapter and the
|
|
596
|
+
standalone server. At 10 req/s per route both versions' p50s are within 5% on
|
|
597
|
+
every compute route. From 50 req/s up, 0.6.2 adds a flat ~40 ms to `rsc` and
|
|
598
|
+
`api`, most of the difference. At 1000 req/s per route:
|
|
599
|
+
|
|
600
|
+
| Route | 0.6.2 | 0.7.0 | Faster |
|
|
601
|
+
| --------------- | ---------- | ---------- | ----------- |
|
|
602
|
+
| `rsc` | 69 / 94 | 25 / 52 | 2.8× / 1.8× |
|
|
603
|
+
| `api` | 67 / 89 | 23 / 47 | 2.9× / 1.9× |
|
|
604
|
+
| `ssr` | 31 / 109 | 29 / 73 | 1.1× / 1.5× |
|
|
605
|
+
| Cold start TTFB | 1844 (p50) | 1390 (p50) | 1.3× |
|
|
606
|
+
|
|
607
|
+
Both sustain at least 6,560 req/s of `ssr`, the load generator's limit.
|
|
608
|
+
|
|
609
|
+
**`NextjsGlobalContainers`**: latency is unchanged, but 0.6.2 served sporadic
|
|
610
|
+
502s under load (5% of `ssr` at 50 req/s per route). Node's default keep-alive
|
|
611
|
+
timeout (5 s) is shorter than the ALB's idle timeout (60 s), so the ALB reused
|
|
612
|
+
connections the server had closed, and CloudFront cached each 502 for its
|
|
613
|
+
10 s error caching TTL. 0.7.0's server outlives the ALB's timeout. `ssr`
|
|
614
|
+
capacity rose from 129 to 194 req/s on two to ten tasks.
|
|
615
|
+
|
|
616
|
+
**`NextjsRegionalContainers`**: with no CDN, every request is the container's,
|
|
617
|
+
and each is several times cheaper. At 10 req/s per route:
|
|
618
|
+
|
|
619
|
+
| Route | 0.6.2 | 0.7.0 | Faster |
|
|
620
|
+
| -------- | --------- | -------- | ----------- |
|
|
621
|
+
| `static` | 197 / 442 | 41 / 163 | 4.8× / 2.7× |
|
|
622
|
+
| `ssr` | 137 / 602 | 22 / 172 | 6.3× / 3.5× |
|
|
623
|
+
| `rsc` | 65 / 275 | 9.4 / 64 | 6.9× / 4.3× |
|
|
624
|
+
| `api` | 62 / 242 | 6.9 / 55 | 8.9× / 4.4× |
|
|
625
|
+
|
|
626
|
+
`ssr` capacity is the same, 675 req/s; `isr` capacity rose from 3,200 to at
|
|
627
|
+
least 6,075 req/s. At 50 req/s on every route at once
|
|
628
|
+
(400 req/s including assets and image optimization), neither version's two
|
|
629
|
+
tasks keep up long enough for autoscaling.
|
|
630
|
+
|
|
631
|
+
**`NextjsRegionalFunctions`**: responses stream through API Gateway, where 0.6.2
|
|
632
|
+
buffered them, and prerendered pages no longer go through the standalone
|
|
633
|
+
server. Rendering itself changed little: `ssr`, `rsc` and `api` p50s are 1.1×
|
|
634
|
+
faster at every rate. At 50 req/s per route:
|
|
635
|
+
|
|
636
|
+
| Route | 0.6.2 | 0.7.0 | Faster |
|
|
637
|
+
| --------------- | ---------- | ---------- | ------------- |
|
|
638
|
+
| `stream` (TTFB) | 231 / 280 | 25 / 84 | 9.2× / 3.3× |
|
|
639
|
+
| `static` | 128 / 231 | 57 / 140 | 2.3× / 1.6× |
|
|
640
|
+
| `isr` | 128 / 229 | 56 / 124 | 2.3× / 1.8× |
|
|
641
|
+
| `image` | 81 / 173 | 125 / 221 | 0.7× (slower) |
|
|
642
|
+
| Cold start TTFB | 2182 (p50) | 1380 (p50) | 1.6× |
|
|
643
|
+
|
|
644
|
+
`ssr` and `isr` capacity are at least 6,560 req/s on both.
|
|
645
|
+
|
|
646
|
+
The Regional constructs' cache hits now check their tags' revalidation markers
|
|
647
|
+
in DynamoDB, in-memory hits included, which is what lets `revalidateTag` reach
|
|
648
|
+
every instance. Each instance holds a marker it read for a second
|
|
649
|
+
(`CDK_NEXTJS_TAG_REFRESH_MS`), since read on every request they capped a
|
|
650
|
+
route's cache hits at about 1,900 req/s: every marker of a deployment shares one
|
|
651
|
+
partition key. The `isr` latencies above predate that TTL; the capacities
|
|
652
|
+
include it.
|
|
653
|
+
|
|
654
|
+
One thing is slower: **image optimization on `NextjsRegionalFunctions`**, 1.5×,
|
|
655
|
+
now that it runs in the server function instead of a dedicated one (see
|
|
656
|
+
[The dedicated image optimization Lambda is gone](#the-dedicated-image-optimization-lambda-is-gone)).
|
|
657
|
+
|
|
658
|
+
0.6.2 also needed two things of the app that 0.7.0 does not: middleware on
|
|
659
|
+
`NextjsRegionalFunctions` to re-add the API Gateway stage to every path, and a
|
|
660
|
+
`Cache-Control` header on every dynamic response, without which CloudFront
|
|
661
|
+
cached it for a day.
|
|
662
|
+
|
|
3
663
|
## 0.6.0
|
|
4
664
|
|
|
5
665
|
### `basePath` is reconciled with your Next.js app's own `basePath`
|
|
@@ -55,9 +715,12 @@ at synth, and derived from the app where there's only one value that can work.
|
|
|
55
715
|
based at `"/base"` — drop the prefix: the prop is now the path as your app
|
|
56
716
|
routes it, and a prefixed value becomes `/base/base/api/health`, which 404s.
|
|
57
717
|
Left as the default `"/api/health"`, nothing changes for you.
|
|
58
|
-
- Static asset pruning is now scoped to the app's S3 key prefix
|
|
59
|
-
|
|
60
|
-
|
|
718
|
+
- Static asset pruning is now scoped to `_next/` under the app's S3 key prefix
|
|
719
|
+
(`<basePath>/_next/`, or `_next/` at the bucket root), so apps or branches
|
|
720
|
+
sharing one bucket under different `basePath`s — including one at the root —
|
|
721
|
+
no longer delete each other's assets once they age past `msTtl`. A file
|
|
722
|
+
removed from `public/` is no longer pruned; delete it by hand if the storage
|
|
723
|
+
matters. One-time cleanup: **if you are
|
|
61
724
|
adding a `basePath` to an existing deployment**, objects already uploaded under
|
|
62
725
|
the old prefix (the bucket root, usually) are outside the new listing and will
|
|
63
726
|
never be pruned. Delete them yourself once after the first deploy.
|
|
@@ -104,7 +767,7 @@ if you want one:
|
|
|
104
767
|
`NextjsRegionalFunctions.nextjsImageFunction` are `undefined` unless the
|
|
105
768
|
dedicated image Lambda is enabled, which no supported prop does yet. A future
|
|
106
769
|
release routes `_next/image` through the adapter runtime after middleware; see
|
|
107
|
-
`docs/
|
|
770
|
+
`docs/adapter-runtime.md`.
|
|
108
771
|
|
|
109
772
|
## 0.5.0
|
|
110
773
|
|