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.
Files changed (263) hide show
  1. package/.jsii +2404 -2723
  2. package/.jsii.tabl.json +1 -1
  3. package/API.md +1681 -1930
  4. package/CLAUDE.md +2 -1
  5. package/README.md +429 -130
  6. package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
  7. package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
  8. package/docs/adapter-runtime.md +185 -0
  9. package/docs/breaking-changes.md +667 -4
  10. package/docs/caching-guide.md +156 -112
  11. package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
  12. package/docs/development-guide.md +1 -1
  13. package/docs/harness-coverage.md +598 -0
  14. package/docs/init-cache-deployment.md +32 -1
  15. package/docs/next-build-output-guide.md +30 -20
  16. package/examples/README.md +5 -1
  17. package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
  18. package/lib/adapter/__fixtures__/app-playground.json +4917 -0
  19. package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
  20. package/lib/adapter/adapter.mjs +1548 -185
  21. package/lib/adapter/adapter.test.js +106 -0
  22. package/lib/adapter/aws-cache-store.d.ts +489 -0
  23. package/lib/adapter/aws-cache-store.js +1004 -0
  24. package/lib/adapter/aws-cache-store.test.d.ts +1 -0
  25. package/lib/adapter/aws-cache-store.test.js +361 -0
  26. package/lib/adapter/build-outputs.d.ts +80 -0
  27. package/lib/adapter/build-outputs.js +852 -0
  28. package/lib/adapter/build-outputs.test.d.ts +1 -0
  29. package/lib/adapter/build-outputs.test.js +861 -0
  30. package/lib/adapter/cache-handler.d.ts +9 -2
  31. package/lib/adapter/cache-handler.js +72 -96
  32. package/lib/adapter/cache-handler.mjs +18956 -17774
  33. package/lib/adapter/cache-handler.test.js +263 -31
  34. package/lib/adapter/cache-kinds.d.ts +32 -0
  35. package/lib/adapter/cache-kinds.js +35 -0
  36. package/lib/adapter/cache-kinds.test.d.ts +1 -0
  37. package/lib/adapter/cache-kinds.test.js +69 -0
  38. package/lib/adapter/cache-utils.d.ts +90 -0
  39. package/lib/adapter/cache-utils.js +199 -4
  40. package/lib/adapter/cache-utils.test.d.ts +1 -0
  41. package/lib/adapter/cache-utils.test.js +179 -0
  42. package/lib/adapter/function-groups.d.ts +215 -0
  43. package/lib/adapter/function-groups.js +1099 -0
  44. package/lib/adapter/function-groups.test.d.ts +1 -0
  45. package/lib/adapter/function-groups.test.js +743 -0
  46. package/lib/adapter/init-cache.d.ts +6 -0
  47. package/lib/adapter/init-cache.js +245 -0
  48. package/lib/adapter/init-cache.test.d.ts +1 -0
  49. package/lib/adapter/init-cache.test.js +137 -0
  50. package/lib/adapter/local-file-cache-handler.d.ts +23 -0
  51. package/lib/adapter/local-file-cache-handler.js +52 -1
  52. package/lib/adapter/memory-cache-handler.d.ts +26 -17
  53. package/lib/adapter/memory-cache-handler.js +32 -50
  54. package/lib/adapter/memory-cache-handler.test.js +105 -85
  55. package/lib/adapter/s3-cache-handler.d.ts +179 -40
  56. package/lib/adapter/s3-cache-handler.js +807 -277
  57. package/lib/adapter/s3-cache-handler.test.js +1186 -31
  58. package/lib/adapter/use-cache-common.d.ts +90 -0
  59. package/lib/adapter/use-cache-common.js +250 -0
  60. package/lib/adapter/use-cache-common.test.d.ts +1 -0
  61. package/lib/adapter/use-cache-common.test.js +646 -0
  62. package/lib/adapter/use-cache-default-handler.d.ts +24 -0
  63. package/lib/adapter/use-cache-default-handler.js +90 -0
  64. package/lib/adapter/use-cache-default-handler.mjs +38645 -0
  65. package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
  66. package/lib/adapter/use-cache-handlers.test.js +349 -0
  67. package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
  68. package/lib/adapter/use-cache-remote-handler.js +186 -0
  69. package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
  70. package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
  71. package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
  72. package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
  73. package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
  74. package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
  75. package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
  76. package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
  77. package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
  78. package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +8 -0
  79. package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
  80. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
  81. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
  82. package/lib/index.d.ts +6 -7
  83. package/lib/index.js +2 -4
  84. package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
  85. package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
  86. package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
  87. package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
  88. package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
  89. package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
  90. package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
  91. package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
  92. package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
  93. package/lib/lambdas/post-deploy/prune-s3.js +41 -12
  94. package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
  95. package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
  96. package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
  97. package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
  98. package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
  99. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
  100. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
  101. package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
  102. package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
  103. package/lib/nextjs-api.d.ts +102 -18
  104. package/lib/nextjs-api.js +338 -38
  105. package/lib/nextjs-api.test.js +537 -1
  106. package/lib/nextjs-build/global-containers.Dockerfile +15 -10
  107. package/lib/nextjs-build/nextjs-build.d.ts +339 -63
  108. package/lib/nextjs-build/nextjs-build.js +684 -327
  109. package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
  110. package/lib/nextjs-build/nextjs-build.test.js +412 -0
  111. package/lib/nextjs-build/patch-fetch.js +1 -1
  112. package/lib/nextjs-build/patch-fetch.test.js +166 -11
  113. package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
  114. package/lib/nextjs-cache.d.ts +82 -4
  115. package/lib/nextjs-cache.js +186 -10
  116. package/lib/nextjs-cache.test.js +176 -1
  117. package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
  118. package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
  119. package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
  120. package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
  121. package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
  122. package/lib/nextjs-compute/nextjs-containers.js +57 -20
  123. package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
  124. package/lib/nextjs-compute/nextjs-functions.js +113 -67
  125. package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
  126. package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
  127. package/lib/nextjs-distribution.d.ts +194 -23
  128. package/lib/nextjs-distribution.js +535 -62
  129. package/lib/nextjs-distribution.test.d.ts +1 -0
  130. package/lib/nextjs-distribution.test.js +697 -0
  131. package/lib/nextjs-post-deploy.d.ts +13 -5
  132. package/lib/nextjs-post-deploy.js +13 -10
  133. package/lib/nextjs-post-deploy.test.d.ts +1 -0
  134. package/lib/nextjs-post-deploy.test.js +34 -0
  135. package/lib/nextjs-static-assets.d.ts +17 -4
  136. package/lib/nextjs-static-assets.js +22 -5
  137. package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
  138. package/lib/root-constructs/nextjs-base-construct.js +139 -47
  139. package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
  140. package/lib/root-constructs/nextjs-global-containers.js +20 -71
  141. package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
  142. package/lib/root-constructs/nextjs-global-functions.js +52 -70
  143. package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
  144. package/lib/root-constructs/nextjs-regional-containers.js +8 -15
  145. package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
  146. package/lib/root-constructs/nextjs-regional-functions.js +8 -26
  147. package/lib/runtime/api-gateway-path.d.ts +34 -0
  148. package/lib/runtime/api-gateway-path.js +71 -0
  149. package/lib/runtime/api-gateway-path.test.d.ts +1 -0
  150. package/lib/runtime/api-gateway-path.test.js +65 -0
  151. package/lib/runtime/case-redirect.d.ts +22 -0
  152. package/lib/runtime/case-redirect.js +63 -0
  153. package/lib/runtime/case-redirect.test.d.ts +1 -0
  154. package/lib/runtime/case-redirect.test.js +32 -0
  155. package/lib/runtime/core.d.ts +234 -0
  156. package/lib/runtime/core.js +1213 -0
  157. package/lib/runtime/core.test.d.ts +1 -0
  158. package/lib/runtime/core.test.js +1678 -0
  159. package/lib/runtime/deployment-root.d.ts +13 -0
  160. package/lib/runtime/deployment-root.js +29 -0
  161. package/lib/runtime/dispatch.d.ts +331 -0
  162. package/lib/runtime/dispatch.js +751 -0
  163. package/lib/runtime/dispatch.test.d.ts +1 -0
  164. package/lib/runtime/dispatch.test.js +853 -0
  165. package/lib/runtime/entrypoints.d.ts +57 -0
  166. package/lib/runtime/entrypoints.js +115 -0
  167. package/lib/runtime/http/abort-signal.d.ts +6 -0
  168. package/lib/runtime/http/abort-signal.js +19 -0
  169. package/lib/runtime/http/abort-signal.test.d.ts +1 -0
  170. package/lib/runtime/http/abort-signal.test.js +49 -0
  171. package/lib/runtime/http/node-server.d.ts +38 -0
  172. package/lib/runtime/http/node-server.js +99 -0
  173. package/lib/runtime/http/node-server.test.d.ts +1 -0
  174. package/lib/runtime/http/node-server.test.js +96 -0
  175. package/lib/runtime/http/node-sink.d.ts +16 -0
  176. package/lib/runtime/http/node-sink.js +48 -0
  177. package/lib/runtime/http/node-sink.test.d.ts +1 -0
  178. package/lib/runtime/http/node-sink.test.js +66 -0
  179. package/lib/runtime/http/request.d.ts +62 -0
  180. package/lib/runtime/http/request.js +134 -0
  181. package/lib/runtime/http/request.test.d.ts +1 -0
  182. package/lib/runtime/http/request.test.js +103 -0
  183. package/lib/runtime/http/response.d.ts +77 -0
  184. package/lib/runtime/http/response.js +229 -0
  185. package/lib/runtime/http/response.test.d.ts +1 -0
  186. package/lib/runtime/http/response.test.js +178 -0
  187. package/lib/runtime/http/sink.d.ts +73 -0
  188. package/lib/runtime/http/sink.js +188 -0
  189. package/lib/runtime/http/sink.test.d.ts +1 -0
  190. package/lib/runtime/http/sink.test.js +257 -0
  191. package/lib/runtime/image-utils.d.ts +78 -0
  192. package/lib/runtime/image-utils.js +129 -0
  193. package/lib/runtime/image-utils.test.d.ts +1 -0
  194. package/lib/runtime/image-utils.test.js +237 -0
  195. package/lib/runtime/image.d.ts +76 -0
  196. package/lib/runtime/image.js +296 -0
  197. package/lib/runtime/image.test.d.ts +1 -0
  198. package/lib/runtime/image.test.js +405 -0
  199. package/lib/runtime/lambda-event.d.ts +4 -0
  200. package/lib/runtime/lambda-event.js +113 -0
  201. package/lib/runtime/lambda-event.test.d.ts +1 -0
  202. package/lib/runtime/lambda-event.test.js +119 -0
  203. package/lib/runtime/lambda.mjs +41595 -0
  204. package/lib/runtime/load-module.d.ts +8 -0
  205. package/lib/runtime/load-module.js +35 -0
  206. package/lib/runtime/manifest.d.ts +215 -0
  207. package/lib/runtime/manifest.js +118 -0
  208. package/lib/runtime/middleware.d.ts +43 -0
  209. package/lib/runtime/middleware.js +113 -0
  210. package/lib/runtime/middleware.test.d.ts +1 -0
  211. package/lib/runtime/middleware.test.js +259 -0
  212. package/lib/runtime/next-modules.d.ts +55 -0
  213. package/lib/runtime/next-modules.js +124 -0
  214. package/lib/runtime/next-modules.test.d.ts +1 -0
  215. package/lib/runtime/next-modules.test.js +34 -0
  216. package/lib/runtime/public-files.d.ts +32 -0
  217. package/lib/runtime/public-files.js +117 -0
  218. package/lib/runtime/public-files.test.d.ts +1 -0
  219. package/lib/runtime/public-files.test.js +97 -0
  220. package/lib/runtime/server.mjs +41588 -0
  221. package/lib/runtime/static-files.d.ts +50 -0
  222. package/lib/runtime/static-files.js +266 -0
  223. package/lib/runtime/static-files.test.d.ts +1 -0
  224. package/lib/runtime/static-files.test.js +118 -0
  225. package/lib/runtime/util.d.ts +28 -0
  226. package/lib/runtime/util.js +79 -0
  227. package/lib/utils/base-path.d.ts +106 -13
  228. package/lib/utils/base-path.js +254 -41
  229. package/lib/utils/base-path.test.js +219 -51
  230. package/lib/utils/get-architecture.d.ts +7 -8
  231. package/lib/utils/get-architecture.js +12 -13
  232. package/lib/utils/zip-directory.d.ts +14 -0
  233. package/lib/utils/zip-directory.js +121 -0
  234. package/lib/utils/zip-directory.test.d.ts +1 -0
  235. package/lib/utils/zip-directory.test.js +99 -0
  236. package/package.json +22 -3
  237. package/scripts/capture-adapter-fixture.mjs +325 -0
  238. package/scripts/e2e-deploy.sh +398 -0
  239. package/scripts/e2e-harness/README.md +707 -0
  240. package/scripts/e2e-harness/app.js +370 -0
  241. package/scripts/e2e-harness/common.sh +249 -0
  242. package/scripts/e2e-harness/screen.mjs +302 -0
  243. package/scripts/e2e-harness/stage-proxy.mjs +145 -0
  244. package/scripts/e2e-harness/type-filters.mjs +47 -0
  245. package/scripts/e2e-logs.sh +75 -0
  246. package/scripts/e2e-offline.sh +91 -0
  247. package/scripts/e2e-sweep.sh +370 -0
  248. package/scripts/e2e-warm.sh +114 -0
  249. package/scripts/zero-config-build.mjs +418 -0
  250. package/docs/1k-concurrent-users-executions.png +0 -0
  251. package/docs/plans/adapter-runtime-release.md +0 -362
  252. package/docs/plans/phase-0-image-function-opt-in.md +0 -295
  253. package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
  254. package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
  255. package/lib/image-optimization/handler-utils.d.ts +0 -34
  256. package/lib/image-optimization/handler-utils.js +0 -83
  257. package/lib/image-optimization/handler-utils.test.js +0 -178
  258. package/lib/nextjs-build/functions.Dockerfile +0 -31
  259. package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
  260. package/lib/nextjs-compute/nextjs-image-function.js +0 -59
  261. package/lib/utils/experimental-flags.d.ts +0 -24
  262. package/lib/utils/experimental-flags.js +0 -30
  263. /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
@@ -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, so apps or
59
- branches sharing one bucket under different `basePath`s no longer delete each
60
- other's assets once they age past `msTtl`. One-time cleanup: **if you are
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/plans/adapter-runtime-release.md`.
770
+ `docs/adapter-runtime.md`.
108
771
 
109
772
  ## 0.5.0
110
773