diff --git a/CHANGELOG.md b/CHANGELOG.md
index b935013783..6a91a2fec4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,8 @@ We manage release notes in this file instead of the paginated Github Releases Pa
Table of Contents
- [React Router Releases](#react-router-releases)
+ - [v8.3.0](#v830)
+ - [RSC Entry Updates](#rsc-entry-updates)
- [v8.2.0](#v820)
- [Web Streams Default Server Entry](#web-streams-default-server-entry)
- [v8.1.0](#v810)
@@ -109,6 +111,117 @@ We manage release notes in this file instead of the paginated Github Releases Pa
+## v8.3.0
+
+Date: 2026-07-22
+
+### What's Changed
+
+#### RSC Entry Updates
+
+This release includes several updates for unstable RSC apps that use custom entry files. Apps using the default RSC Framework entries do not need any changes.
+
+If you maintain custom RSC entries, review the generated unstable change notes for the new client version, subresource integrity, and CSP nonce wiring. Custom `entry.rsc.tsx` files should pass the generated client version to `unstable_matchRSCServerRequest`, and custom `entry.ssr.tsx` files may need to pass the generated import map integrity data and request nonce through React's HTML renderer.
+
+### Minor Changes
+
+- `@react-router/dev` - Restart `react-router dev` with `--conditions=development` when not already configured ([#15291](https://github.com/remix-run/react-router/pull/15291))
+
+### Patch Changes
+
+- `react-router` - Encode path params in `href`/`generatePath` per RFC 3986 path-segment rules instead of `encodeURIComponent` ([#15310](https://github.com/remix-run/react-router/pull/15310))
+ - Characters that are valid literally in a path segment (`$ & + , ; = : @` — RFC 3986 `pchar`) are no longer percent-encoded, so values like a semver build `1.0.0+1` interpolate unchanged instead of becoming `1.0.0%2B1`
+ - Structural/unsafe characters (`/ ? # %`, whitespace, non-ASCII) are still escaped exactly as before
+- `react-router` - Use `crypto.randomUUID()` for `createMemorySessionStorage` session ids ([#15302](https://github.com/remix-run/react-router/pull/15302))
+ - `createMemorySessionStorage` is only intended for local development and testing - sessions are lost when the server restarts
+- `react-router` - Fix `NavLink` not applying its `pending` state when `to` has a trailing slash ([#15300](https://github.com/remix-run/react-router/pull/15300))
+- `@react-router/architect` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- `@react-router/cloudflare` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- `@react-router/dev` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- `@react-router/express` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- `@react-router/fs-routes` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- `@react-router/node` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- `@react-router/remix-routes-option-adapter` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+
+### Unstable Changes
+
+⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
+
+- `react-router` - Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements ([#15323](https://github.com/remix-run/react-router/pull/15323))
+- `react-router` - Harden RSC CSRF code paths ([#15311](https://github.com/remix-run/react-router/pull/15311))
+- `react-router` - Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush ([#15286](https://github.com/remix-run/react-router/pull/15286))
+ - Handle cancellation of the `injectRSCPayload` readable side, clear the pending flush, and cancel the underlying RSC payload stream
+- `react-router` - Detect stale RSC clients during lazy route discovery and reload the destination document ([#15318](https://github.com/remix-run/react-router/pull/15318))
+
+ #### Migration
+
+ Apps using the default RSC Framework entry do not need to make any changes. Apps with a custom `entry.rsc.tsx` should import the generated client version and pass it to `unstable_matchRSCServerRequest`:
+
+ ```tsx
+ import clientVersion from "virtual:react-router/unstable_rsc/client-version";
+
+ return unstable_matchRSCServerRequest({
+ // ...
+ clientVersion,
+ });
+ ```
+
+- `react-router` - Add CSP nonce support to RSC document rendering ([#15320](https://github.com/remix-run/react-router/pull/15320))
+ - Add `nonce` options to `unstable_routeRSCServerRequest` and `unstable_RSCStaticRouter`
+ - Forward the nonce to the HTML renderer and apply it to injected RSC payload scripts and nonce-aware framework components
+
+ To adopt nonce-based CSP, update your `entry.ssr.tsx` (run `react-router reveal entry.ssr` first in RSC Framework Mode) to generate a fresh nonce for each request. Pass it to `routeRSCServerRequest`, spread the `renderHTML` options into React's HTML renderer, pass `options.nonce` to `RSCStaticRouter`, and use the same nonce in the `Content-Security-Policy` response header:
+
+ ```tsx
+ const nonce = crypto.randomUUID();
+ const response = await routeRSCServerRequest({
+ request,
+ serverResponse,
+ createFromReadableStream,
+ nonce,
+ async renderHTML(getPayload, options) {
+ const payload = getPayload();
+ return renderHTMLToReadableStream(
+ ,
+ {
+ ...options,
+ bootstrapScriptContent,
+ formState: await payload.formState,
+ signal: request.signal,
+ },
+ );
+ },
+ });
+ response.headers.set(
+ "Content-Security-Policy",
+ `script-src 'self' 'nonce-${nonce}'`,
+ );
+ ```
+
+- `@react-router/dev` - Add `unstable_rsc/client-version` client build version virtual module ([#15318](https://github.com/remix-run/react-router/pull/15318))
+
+- `@react-router/dev` - Support the `subResourceIntegrity` config option in RSC Framework Mode ([#15321](https://github.com/remix-run/react-router/pull/15321))
+
+ #### Migration guide
+
+ No changes are required when using the default RSC SSR entry. If you maintain a custom `app/entry.ssr.tsx`, import the new virtual module and pass its hashes to React's `importMap` render option:
+
+ ```diff
+ +import subResourceIntegrity from "virtual:react-router/unstable_rsc/subresource-integrity";
+
+ return renderToReadableStream(, {
+ ...options,
+ bootstrapScriptContent,
+ formState,
+ + importMap: subResourceIntegrity
+ + ? { integrity: subResourceIntegrity }
+ + : undefined,
+ signal: request.signal,
+ });
+ ```
+
+**Full Changelog**: [`v8.2.0...v8.3.0`](https://github.com/remix-run/react-router/compare/react-router@8.2.0...react-router@8.3.0)
+
## v8.2.0
Date: 2026-07-08
diff --git a/packages/create-react-router/CHANGELOG.md b/packages/create-react-router/CHANGELOG.md
index ac095d86de..8f76964af6 100644
--- a/packages/create-react-router/CHANGELOG.md
+++ b/packages/create-react-router/CHANGELOG.md
@@ -1,5 +1,11 @@
# `create-react-router`
+## v8.3.0
+
+### Patch Changes
+
+- _No changes_
+
## v8.2.0
### Minor Changes
diff --git a/packages/create-react-router/package.json b/packages/create-react-router/package.json
index ca37d076e5..591f0198ff 100644
--- a/packages/create-react-router/package.json
+++ b/packages/create-react-router/package.json
@@ -1,7 +1,7 @@
{
"name": "create-react-router",
"type": "module",
- "version": "8.2.0",
+ "version": "8.3.0",
"description": "Create a new React Router app",
"homepage": "https://reactrouter.com",
"bugs": {
diff --git a/packages/react-router-architect/CHANGELOG.md b/packages/react-router-architect/CHANGELOG.md
index 9801e8cae5..b00158fb5b 100644
--- a/packages/react-router-architect/CHANGELOG.md
+++ b/packages/react-router-architect/CHANGELOG.md
@@ -1,5 +1,14 @@
# `@react-router/architect`
+## v8.3.0
+
+### Patch Changes
+
+- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- Updated dependencies:
+ - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0)
+ - [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0)
+
## v8.2.0
### Patch Changes
diff --git a/packages/react-router-architect/package.json b/packages/react-router-architect/package.json
index 0cc770f96b..9f34612754 100644
--- a/packages/react-router-architect/package.json
+++ b/packages/react-router-architect/package.json
@@ -1,7 +1,7 @@
{
"name": "@react-router/architect",
"type": "module",
- "version": "8.2.0",
+ "version": "8.3.0",
"description": "Architect server request handler for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
@@ -61,7 +61,7 @@
"peerDependencies": {
"@react-router/node": "workspace:^",
"react-router": "workspace:^",
- "typescript": "^5.1.0 || ^6.0.0"
+ "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0"
},
"peerDependenciesMeta": {
"typescript": {
diff --git a/packages/react-router-cloudflare/CHANGELOG.md b/packages/react-router-cloudflare/CHANGELOG.md
index 40637211dc..e8d293c861 100644
--- a/packages/react-router-cloudflare/CHANGELOG.md
+++ b/packages/react-router-cloudflare/CHANGELOG.md
@@ -1,5 +1,13 @@
# `@react-router/cloudflare`
+## v8.3.0
+
+### Patch Changes
+
+- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- Updated dependencies:
+ - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0)
+
## v8.2.0
### Patch Changes
diff --git a/packages/react-router-cloudflare/package.json b/packages/react-router-cloudflare/package.json
index 44b10eb9c3..54c3e287e2 100644
--- a/packages/react-router-cloudflare/package.json
+++ b/packages/react-router-cloudflare/package.json
@@ -1,7 +1,7 @@
{
"name": "@react-router/cloudflare",
"type": "module",
- "version": "8.2.0",
+ "version": "8.3.0",
"description": "Cloudflare platform abstractions for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
@@ -50,7 +50,7 @@
"peerDependencies": {
"@cloudflare/workers-types": "^4.0.0",
"react-router": "workspace:^",
- "typescript": "^5.1.0 || ^6.0.0"
+ "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0"
},
"peerDependenciesMeta": {
"typescript": {
diff --git a/packages/react-router-dev/.changes/minor.development-conditions.md b/packages/react-router-dev/.changes/minor.development-conditions.md
deleted file mode 100644
index 423b22f725..0000000000
--- a/packages/react-router-dev/.changes/minor.development-conditions.md
+++ /dev/null
@@ -1 +0,0 @@
-Restart `react-router dev` with `--conditions=development` when not already configured
diff --git a/packages/react-router-dev/.changes/unstable.rsc-client-version.md b/packages/react-router-dev/.changes/unstable.rsc-client-version.md
deleted file mode 100644
index 001cc296b0..0000000000
--- a/packages/react-router-dev/.changes/unstable.rsc-client-version.md
+++ /dev/null
@@ -1 +0,0 @@
-Add `unstable_rsc/client-version` client build version virtual module
diff --git a/packages/react-router-dev/.changes/unstable.rsc-subresource-integrity.md b/packages/react-router-dev/.changes/unstable.rsc-subresource-integrity.md
deleted file mode 100644
index 01a1047593..0000000000
--- a/packages/react-router-dev/.changes/unstable.rsc-subresource-integrity.md
+++ /dev/null
@@ -1,19 +0,0 @@
-Support the `subResourceIntegrity` config option in RSC Framework Mode
-
-#### Migration guide
-
-No changes are required when using the default RSC SSR entry. If you maintain a custom `app/entry.ssr.tsx`, import the new virtual module and pass its hashes to React's `importMap` render option:
-
-```diff
-+import subResourceIntegrity from "virtual:react-router/unstable_rsc/subresource-integrity";
-
-return renderToReadableStream(, {
- ...options,
- bootstrapScriptContent,
- formState,
-+ importMap: subResourceIntegrity
-+ ? { integrity: subResourceIntegrity }
-+ : undefined,
- signal: request.signal,
-});
-```
diff --git a/packages/react-router-dev/CHANGELOG.md b/packages/react-router-dev/CHANGELOG.md
index 886f5ded0c..ffb149f4b0 100644
--- a/packages/react-router-dev/CHANGELOG.md
+++ b/packages/react-router-dev/CHANGELOG.md
@@ -1,5 +1,46 @@
# `@react-router/dev`
+## v8.3.0
+
+### Minor Changes
+
+- Restart `react-router dev` with `--conditions=development` when not already configured ([#15291](https://github.com/remix-run/react-router/pull/15291))
+
+### Patch Changes
+
+- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+
+### Unstable Changes
+
+⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
+
+- Add `unstable_rsc/client-version` client build version virtual module ([#15318](https://github.com/remix-run/react-router/pull/15318))
+
+- Support the `subResourceIntegrity` config option in RSC Framework Mode ([#15321](https://github.com/remix-run/react-router/pull/15321))
+
+ #### Migration guide
+
+ No changes are required when using the default RSC SSR entry. If you maintain a custom `app/entry.ssr.tsx`, import the new virtual module and pass its hashes to React's `importMap` render option:
+
+ ```diff
+ +import subResourceIntegrity from "virtual:react-router/unstable_rsc/subresource-integrity";
+
+ return renderToReadableStream(, {
+ ...options,
+ bootstrapScriptContent,
+ formState,
+ + importMap: subResourceIntegrity
+ + ? { integrity: subResourceIntegrity }
+ + : undefined,
+ signal: request.signal,
+ });
+ ```
+
+- Updated dependencies:
+ - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0)
+ - [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0)
+ - [`@react-router/serve@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/serve@8.3.0)
+
## v8.2.0
### Minor Changes
diff --git a/packages/react-router-dev/package.json b/packages/react-router-dev/package.json
index 68460fe48f..7f25d822c1 100644
--- a/packages/react-router-dev/package.json
+++ b/packages/react-router-dev/package.json
@@ -1,7 +1,7 @@
{
"name": "@react-router/dev",
"type": "module",
- "version": "8.2.0",
+ "version": "8.3.0",
"description": "Dev tools and CLI for React Router",
"keywords": [
"react",
@@ -144,7 +144,7 @@
"@vitejs/plugin-rsc": "catalog:",
"react-router": "workspace:^",
"react-server-dom-webpack": "catalog:",
- "typescript": "^5.1.0 || ^6.0.0",
+ "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0",
"vite": "^7.0.0 || ^8.0.0",
"wrangler": "^4.0.0"
},
diff --git a/packages/react-router-express/CHANGELOG.md b/packages/react-router-express/CHANGELOG.md
index 9140efdf0b..8971e53f07 100644
--- a/packages/react-router-express/CHANGELOG.md
+++ b/packages/react-router-express/CHANGELOG.md
@@ -1,5 +1,14 @@
# `@react-router/express`
+## v8.3.0
+
+### Patch Changes
+
+- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- Updated dependencies:
+ - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0)
+ - [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0)
+
## v8.2.0
### Patch Changes
diff --git a/packages/react-router-express/package.json b/packages/react-router-express/package.json
index 92d36d8ece..a021fca8d8 100644
--- a/packages/react-router-express/package.json
+++ b/packages/react-router-express/package.json
@@ -1,7 +1,7 @@
{
"name": "@react-router/express",
"type": "module",
- "version": "8.2.0",
+ "version": "8.3.0",
"description": "Express server request handler for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
@@ -57,7 +57,7 @@
"peerDependencies": {
"express": "^4.22.2 || ^5",
"react-router": "workspace:*",
- "typescript": "^5.1.0 || ^6.0.0"
+ "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0"
},
"peerDependenciesMeta": {
"typescript": {
diff --git a/packages/react-router-fs-routes/CHANGELOG.md b/packages/react-router-fs-routes/CHANGELOG.md
index c5a54a047d..23841a9f84 100644
--- a/packages/react-router-fs-routes/CHANGELOG.md
+++ b/packages/react-router-fs-routes/CHANGELOG.md
@@ -1,5 +1,13 @@
# `@react-router/fs-routes`
+## v8.3.0
+
+### Patch Changes
+
+- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- Updated dependencies:
+ - [`@react-router/dev@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/dev@8.3.0)
+
## v8.2.0
### Patch Changes
diff --git a/packages/react-router-fs-routes/package.json b/packages/react-router-fs-routes/package.json
index d220813406..4ff1b3269f 100644
--- a/packages/react-router-fs-routes/package.json
+++ b/packages/react-router-fs-routes/package.json
@@ -1,7 +1,7 @@
{
"name": "@react-router/fs-routes",
"type": "module",
- "version": "8.2.0",
+ "version": "8.3.0",
"description": "File system routing conventions for React Router, for use within routes.ts",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
@@ -51,7 +51,7 @@
},
"peerDependencies": {
"@react-router/dev": "workspace:^",
- "typescript": "^5.1.0 || ^6.0.0"
+ "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0"
},
"peerDependenciesMeta": {
"typescript": {
diff --git a/packages/react-router-node/CHANGELOG.md b/packages/react-router-node/CHANGELOG.md
index efe82bbc88..82fd7243bc 100644
--- a/packages/react-router-node/CHANGELOG.md
+++ b/packages/react-router-node/CHANGELOG.md
@@ -1,5 +1,13 @@
# `@react-router/node`
+## v8.3.0
+
+### Patch Changes
+
+- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- Updated dependencies:
+ - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0)
+
## v8.2.0
### Patch Changes
diff --git a/packages/react-router-node/package.json b/packages/react-router-node/package.json
index 27f09bfe2a..c030b65222 100644
--- a/packages/react-router-node/package.json
+++ b/packages/react-router-node/package.json
@@ -1,7 +1,7 @@
{
"name": "@react-router/node",
"type": "module",
- "version": "8.2.0",
+ "version": "8.3.0",
"description": "Node.js platform abstractions for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
@@ -53,7 +53,7 @@
},
"peerDependencies": {
"react-router": "workspace:*",
- "typescript": "^5.1.0 || ^6.0.0"
+ "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0"
},
"peerDependenciesMeta": {
"typescript": {
diff --git a/packages/react-router-remix-routes-option-adapter/CHANGELOG.md b/packages/react-router-remix-routes-option-adapter/CHANGELOG.md
index f1dcea567c..0f2d219194 100644
--- a/packages/react-router-remix-routes-option-adapter/CHANGELOG.md
+++ b/packages/react-router-remix-routes-option-adapter/CHANGELOG.md
@@ -1,5 +1,13 @@
# `@react-router/remix-config-routes-adapter`
+## v8.3.0
+
+### Patch Changes
+
+- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
+- Updated dependencies:
+ - [`@react-router/dev@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/dev@8.3.0)
+
## v8.2.0
### Patch Changes
diff --git a/packages/react-router-remix-routes-option-adapter/package.json b/packages/react-router-remix-routes-option-adapter/package.json
index bad639636c..1c5eb57da4 100644
--- a/packages/react-router-remix-routes-option-adapter/package.json
+++ b/packages/react-router-remix-routes-option-adapter/package.json
@@ -1,7 +1,7 @@
{
"name": "@react-router/remix-routes-option-adapter",
"type": "module",
- "version": "8.2.0",
+ "version": "8.3.0",
"description": "Adapter for Remix's \"routes\" config option, for use within routes.ts",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
@@ -47,7 +47,7 @@
},
"peerDependencies": {
"@react-router/dev": "workspace:^",
- "typescript": "^5.1.0 || ^6.0.0"
+ "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0"
},
"peerDependenciesMeta": {
"typescript": {
diff --git a/packages/react-router-serve/CHANGELOG.md b/packages/react-router-serve/CHANGELOG.md
index 446ea33f1e..4466b07bf9 100644
--- a/packages/react-router-serve/CHANGELOG.md
+++ b/packages/react-router-serve/CHANGELOG.md
@@ -1,5 +1,14 @@
# `@react-router/serve`
+## v8.3.0
+
+### Patch Changes
+
+- Updated dependencies:
+ - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0)
+ - [`@react-router/express@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/express@8.3.0)
+ - [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0)
+
## v8.2.0
### Patch Changes
diff --git a/packages/react-router-serve/package.json b/packages/react-router-serve/package.json
index e4bb702106..906ef0f3f3 100644
--- a/packages/react-router-serve/package.json
+++ b/packages/react-router-serve/package.json
@@ -1,7 +1,7 @@
{
"name": "@react-router/serve",
"type": "module",
- "version": "8.2.0",
+ "version": "8.3.0",
"description": "Production application server for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router/.changes/patch.encode-path-params-pchar.md b/packages/react-router/.changes/patch.encode-path-params-pchar.md
deleted file mode 100644
index 811f55cafe..0000000000
--- a/packages/react-router/.changes/patch.encode-path-params-pchar.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Encode path params in `href`/`generatePath` per RFC 3986 path-segment rules instead of `encodeURIComponent`
-
-- Characters that are valid literally in a path segment (`$ & + , ; = : @` — RFC 3986 `pchar`) are no longer percent-encoded, so values like a semver build `1.0.0+1` interpolate unchanged instead of becoming `1.0.0%2B1`
-- Structural/unsafe characters (`/ ? # %`, whitespace, non-ASCII) are still escaped exactly as before
diff --git a/packages/react-router/.changes/patch.memory-session-random-uuid.md b/packages/react-router/.changes/patch.memory-session-random-uuid.md
deleted file mode 100644
index a201faead7..0000000000
--- a/packages/react-router/.changes/patch.memory-session-random-uuid.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Use `crypto.randomUUID()` for `createMemorySessionStorage` session ids
-
-- `createMemorySessionStorage` is only intended for local development and testing - sessions are lost when the server restarts
diff --git a/packages/react-router/.changes/patch.navlink-pending-trailing-slash.md b/packages/react-router/.changes/patch.navlink-pending-trailing-slash.md
deleted file mode 100644
index 085ad0f54f..0000000000
--- a/packages/react-router/.changes/patch.navlink-pending-trailing-slash.md
+++ /dev/null
@@ -1 +0,0 @@
-Fix `NavLink` not applying its `pending` state when `to` has a trailing slash
diff --git a/packages/react-router/.changes/patch.rsc-client-loader-revalidation.md b/packages/react-router/.changes/patch.rsc-client-loader-revalidation.md
deleted file mode 100644
index f3df2a93aa..0000000000
--- a/packages/react-router/.changes/patch.rsc-client-loader-revalidation.md
+++ /dev/null
@@ -1 +0,0 @@
-Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements.
diff --git a/packages/react-router/.changes/patch.rsc-csrf.md b/packages/react-router/.changes/patch.rsc-csrf.md
deleted file mode 100644
index f778a415cf..0000000000
--- a/packages/react-router/.changes/patch.rsc-csrf.md
+++ /dev/null
@@ -1 +0,0 @@
-Harden RSC CSRF codepaths.
diff --git a/packages/react-router/.changes/patch.rsc-html-stream-cancel.md b/packages/react-router/.changes/patch.rsc-html-stream-cancel.md
deleted file mode 100644
index 322d3e5488..0000000000
--- a/packages/react-router/.changes/patch.rsc-html-stream-cancel.md
+++ /dev/null
@@ -1 +0,0 @@
-Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush — `injectRSCPayload` now handles cancellation of its readable side, clears the pending flush, and cancels the underlying RSC payload stream
diff --git a/packages/react-router/.changes/unstable.rsc-client-version.md b/packages/react-router/.changes/unstable.rsc-client-version.md
deleted file mode 100644
index 66d652cf88..0000000000
--- a/packages/react-router/.changes/unstable.rsc-client-version.md
+++ /dev/null
@@ -1,14 +0,0 @@
-Detect stale RSC clients during lazy route discovery and reload the destination document
-
-#### Migration
-
-Apps using the default RSC Framework entry do not need to make any changes. Apps with a custom `entry.rsc.tsx` should import the generated client version and pass it to `unstable_matchRSCServerRequest`:
-
-```tsx
-import clientVersion from "virtual:react-router/unstable_rsc/client-version";
-
-return unstable_matchRSCServerRequest({
- // ...
- clientVersion,
-});
-```
diff --git a/packages/react-router/.changes/unstable.rsc-nonce.md b/packages/react-router/.changes/unstable.rsc-nonce.md
deleted file mode 100644
index b4ce627b20..0000000000
--- a/packages/react-router/.changes/unstable.rsc-nonce.md
+++ /dev/null
@@ -1,32 +0,0 @@
-Add CSP nonce support to RSC document rendering
-
-- Add `nonce` options to `unstable_routeRSCServerRequest` and `unstable_RSCStaticRouter`
-- Forward the nonce to the HTML renderer and apply it to injected RSC payload scripts and nonce-aware framework components
-
-To adopt nonce-based CSP, update your `entry.ssr.tsx` (run `react-router reveal entry.ssr` first in RSC Framework Mode) to generate a fresh nonce for each request. Pass it to `routeRSCServerRequest`, spread the `renderHTML` options into React's HTML renderer, pass `options.nonce` to `RSCStaticRouter`, and use the same nonce in the `Content-Security-Policy` response header:
-
-```tsx
-const nonce = crypto.randomUUID();
-const response = await routeRSCServerRequest({
- request,
- serverResponse,
- createFromReadableStream,
- nonce,
- async renderHTML(getPayload, options) {
- const payload = getPayload();
- return renderHTMLToReadableStream(
- ,
- {
- ...options,
- bootstrapScriptContent,
- formState: await payload.formState,
- signal: request.signal,
- },
- );
- },
-});
-response.headers.set(
- "Content-Security-Policy",
- `script-src 'self' 'nonce-${nonce}'`,
-);
-```
diff --git a/packages/react-router/CHANGELOG.md b/packages/react-router/CHANGELOG.md
index 2883614256..45abf9f3f4 100644
--- a/packages/react-router/CHANGELOG.md
+++ b/packages/react-router/CHANGELOG.md
@@ -1,5 +1,71 @@
# `react-router`
+## v8.3.0
+
+### Patch Changes
+
+- Encode path params in `href`/`generatePath` per RFC 3986 path-segment rules instead of `encodeURIComponent` ([#15310](https://github.com/remix-run/react-router/pull/15310))
+ - Characters that are valid literally in a path segment (`$ & + , ; = : @` — RFC 3986 `pchar`) are no longer percent-encoded, so values like a semver build `1.0.0+1` interpolate unchanged instead of becoming `1.0.0%2B1`
+ - Structural/unsafe characters (`/ ? # %`, whitespace, non-ASCII) are still escaped exactly as before
+- Use `crypto.randomUUID()` for `createMemorySessionStorage` session ids ([#15302](https://github.com/remix-run/react-router/pull/15302))
+ - `createMemorySessionStorage` is only intended for local development and testing - sessions are lost when the server restarts
+- Fix `NavLink` not applying its `pending` state when `to` has a trailing slash ([#15300](https://github.com/remix-run/react-router/pull/15300))
+- Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements ([#15323](https://github.com/remix-run/react-router/pull/15323))
+- Harden RSC CSRF code paths ([#15311](https://github.com/remix-run/react-router/pull/15311))
+- Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush ([#15286](https://github.com/remix-run/react-router/pull/15286))
+ - Handle cancellation of the `injectRSCPayload` readable side, clear the pending flush, and cancel the underlying RSC payload stream
+
+### Unstable Changes
+
+⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
+
+- Detect stale RSC clients during lazy route discovery and reload the destination document ([#15318](https://github.com/remix-run/react-router/pull/15318))
+
+ #### Migration
+
+ Apps using the default RSC Framework entry do not need to make any changes. Apps with a custom `entry.rsc.tsx` should import the generated client version and pass it to `unstable_matchRSCServerRequest`:
+
+ ```tsx
+ import clientVersion from "virtual:react-router/unstable_rsc/client-version";
+
+ return unstable_matchRSCServerRequest({
+ // ...
+ clientVersion,
+ });
+ ```
+
+- Add CSP nonce support to RSC document rendering ([#15320](https://github.com/remix-run/react-router/pull/15320))
+ - Add `nonce` options to `unstable_routeRSCServerRequest` and `unstable_RSCStaticRouter`
+ - Forward the nonce to the HTML renderer and apply it to injected RSC payload scripts and nonce-aware framework components
+
+ To adopt nonce-based CSP, update your `entry.ssr.tsx` (run `react-router reveal entry.ssr` first in RSC Framework Mode) to generate a fresh nonce for each request. Pass it to `routeRSCServerRequest`, spread the `renderHTML` options into React's HTML renderer, pass `options.nonce` to `RSCStaticRouter`, and use the same nonce in the `Content-Security-Policy` response header:
+
+ ```tsx
+ const nonce = crypto.randomUUID();
+ const response = await routeRSCServerRequest({
+ request,
+ serverResponse,
+ createFromReadableStream,
+ nonce,
+ async renderHTML(getPayload, options) {
+ const payload = getPayload();
+ return renderHTMLToReadableStream(
+ ,
+ {
+ ...options,
+ bootstrapScriptContent,
+ formState: await payload.formState,
+ signal: request.signal,
+ },
+ );
+ },
+ });
+ response.headers.set(
+ "Content-Security-Policy",
+ `script-src 'self' 'nonce-${nonce}'`,
+ );
+ ```
+
## v8.2.0
### Patch Changes
diff --git a/packages/react-router/package.json b/packages/react-router/package.json
index db9c66f667..91528904fc 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -1,7 +1,7 @@
{
"name": "react-router",
"type": "module",
- "version": "8.2.0",
+ "version": "8.3.0",
"description": "Declarative routing for React",
"keywords": [
"react",