### What?
Reverts #94617, which had reverted #94610. This re-lands the
stabilization of the `catchError` API and the `retry` error prop by
removing their `unstable_` prefix across source, docs, and tests.
### Why?
#94610 was reverted in #94617 to unblock another change. This re-applies
it now that it is no longer blocked.
### How?
`git revert` of the revert commit. The repo's custom errors.json merge
driver handled the error registry: the original codes `1324`/`1325` had
been reclaimed by `instant` errors after the revert, so the reintroduced
messages were minted as new codes `1360` (`retry()` can only be used in
the App Router) and `1361` (`catchError` can only be used in Client
Components), keeping errors.json append-only.
The docs changelog adds `v16.3.0 | catchError became stable.` while
retaining the historical `v16.2.0 | unstable_catchError introduced.`
row.
### Verification
- `pnpm update-error-codes` (check_error_codes passes; errors.json in
sync)
- `pnpm build` (full JS build, exit 0)
- `pnpm --filter=next types` (exit 0)
- Not run: Rust/cargo build (`react_server_components.rs` change is a
one-line allow-list string revert; left to CI)
<!-- NEXT_JS_LLM_PR -->
### What?
Promotes two experimental error-handling APIs to stable by dropping the
`unstable_` prefix:
- `unstable_catchError` → `catchError` (exported from `next/error`)
- `unstable_retry` → `retry` (the prop Next.js injects into `error.js` /
`global-error.js` boundaries and `catchError` fallbacks)
### Why?
Both were introduced as `unstable_` in `v16.2.0` and are now stable as
of `v16.3.0`. The experimental prefix should be removed from the stable
surface.
### How?
- Renamed the `next/error` export (`error.d.ts`, `error.js`,
`src/api/error.ts`, `src/api/error.react-server.ts`) and the
implementation in `client/components/catch-error.tsx`.
- Renamed the framework-injected `retry` prop across
`error-boundary.tsx`, `builtin/global-error.tsx`, the dev-overlay error
boundary, and the `ErrorInfo` type.
- Updated the RSC client-only export list in the SWC transform
(`react_server_components.rs`) so importing `catchError` in a Server
Component still produces the "only available in Client Components"
error.
- Updated the thrown error messages and their `errors.json` entries
(codes 1138/1139), the TypeScript-plugin serialization-exemption rule,
all affected tests, the rspack test manifests, and the docs.
- Docs version-history tables keep the historical `unstable_` rows and
add a `v16.3.0` row noting the rename to stable.
This is a clean rename with **no** backward-compatible `unstable_`
alias.
### Verification
- Passed: pre-commit hooks (`prettier`, `eslint --fix`, `rustfmt`) on
all 35 changed files.
- Passed: repo-wide grep confirms no remaining `unstable_catchError` /
`unstable_retry` outside the intended historical version-history rows.
- In progress locally (covered by CI): `pnpm build-all` (native SWC
still compiling on a fresh worktree), then `pnpm --filter=next types`
and the targeted e2e suites (`app-dir/catch-error`, `app-dir/errors`,
`rsc-build-errors`, typescript-plugin `client-boundary`).
<!-- NEXT_JS_LLM_PR -->
This PR adds `unstable_catchError()` API for a granular custom error
boundary. The error component generated by this API is not a true
component format, as the wrapper provides additional args. Therefore,
the API is a function call by design rather than a boundary component to
avoid merging the `errorInfo` with the user-provided props from the
wrapper.
This API works for both the App/Pages Router. However, `retry()` is not
allowed in Pages Router as it depends on `router.refresh()`, and will
throw. Also, it's exported from `next/error` as there was already an
`Error` component for the [Pages
Router](https://nextjs.org/docs/pages/building-your-application/routing/custom-error#reusing-the-built-in-error-page).
### DevTools
<img width="508" height="90" alt="CleanShot 2026-03-13 at 03 02 46@2x"
src="https://github.com/user-attachments/assets/8b79b1f6-877d-4901-99f7-6a2b4d3e34fe"
/>
Docs to follow up: https://github.com/vercel/next.js/pull/89847
Closes NAR-768
---------
Co-authored-by: Josh Story <story@hey.com>
Alias all existing imports from `next/dist/..` to `next/dist/esm` for edge compiler. So that we don't need checking for `process.env.NEXT_RUNTIME === 'edge'` or passing down `nextRuntime` to decide wether the esm or cjs asset to require
This will also fix the issue that some layouts hook are been included twice into the bundle with cjs and esm bundle in edge runtime, now only esm chunk will be bundled in server.
Re-do of https://github.com/vercel/next.js/pull/40251
Edge SSR'd routes cold boot performances are proportional to the
executed code size.
In order to improve it, we are trying to optimize for the bundle size of
a packed Edge SSR route.
This PR adds ESM compilation targets for all Next.js dist packages and
use them to bundle Edge SSR'd route.
This allows us to leverage the better tree shaking/DCE for ESM modules
in webpack in order to decrease the overall bundle size.
This PR also enables minifying Edge SSR routes. Since we don't control
which minifier might be used later (if any), it's best if we provide an
already optimised bundle.
<img width="903" alt="image"
src="https://user-images.githubusercontent.com/11064311/190005211-b7cb2c58-a56a-44b0-8ee4-fd3f603e41bd.png">
This is a 10ms cold boot win per my benchmarking script, which I'll put
in a subsequent PR.
Not done yet:
- ~~swap exported requires in `next/link` (and others) etc to point them
to the esm modules version~~
<!--
Thanks for opening a PR! Your contribution is much appreciated. In order
to make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below. Choose the right checklist for
the change that you're making: -->
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
- [x] Implements an existing feature request or RFC. Make sure the
feature request has been accepted for implementation before opening a
PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The examples guidelines are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: Shu Ding <g@shud.in>
<!--
Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change that you're making:
-->
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have a helpful link attached, see `contributing.md`
## Feature
- [ ] Implements an existing feature request or RFC. Make sure the
feature request has been accepted for implementation before opening a
PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have a helpful link attached, see `contributing.md`
## Documentation / Examples
- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The "examples guidelines" are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: Shu Ding <g@shud.in>
This reverts commit 11deaaa82b.
Temporarily reverts the above commit due to breaking middleware/edge
functions once deployed.
Fixes:
https://github.com/vercel/next.js/actions/runs/3133433920/jobs/5087331787
cc @shuding @feedthejim
```sh
[GET] /blog/first
13:56:56:61
2022-09-27T20:56:56.671Z 61d43a6a-34a1-40c0-b71f-4ae5d1918431 ERROR /var/task/node_modules/next/dist/esm/client/router.js:1
/* global window */ import React from 'react';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1033:15)
at Module._compile (node:internal/modules/cjs/loader:1069:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Module.require (node:internal/modules/cjs/loader:1005:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object.<anonymous> (/var/task/node_modules/next/router.js:3:7)
at Module._compile (node:internal/modules/cjs/loader:1105:14)
```
# Context
Edge SSR'd routes cold boot performances are proportional to the
executed code size.
In order to improve it, we are trying to optimize for the bundle size of
a packed Edge SSR route.
This PR adds ESM compilation targets for all Next.js dist packages and
use them to bundle Edge SSR'd route.
This allows us to leverage the better tree shaking/DCE for ESM modules
in webpack in order to decrease the overall bundle size.
This PR also enables minifying Edge SSR routes. Since we don't control
which minifier might be used later (if any), it's best if we provide an
already optimised bundle.
<img width="903" alt="image"
src="https://user-images.githubusercontent.com/11064311/190005211-b7cb2c58-a56a-44b0-8ee4-fd3f603e41bd.png">
This is a 10ms cold boot win per my benchmarking script, which I'll put
in a subsequent PR.
Not done yet:
- ~~swap exported requires in `next/link` (and others) etc to point them
to the esm modules version~~
<!--
Thanks for opening a PR! Your contribution is much appreciated.
In order to make sure your PR is handled as smoothly as possible we
request that you follow the checklist sections below.
Choose the right checklist for the change that you're making:
-->
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [x] Implements an existing feature request or RFC. Make sure the
feature request has been accepted for implementation before opening a
PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
## Documentation / Examples
- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The examples guidelines are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: Shu Ding <g@shud.in>