# `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 - Fix `href()` to properly stringify and URL-encode param values, matching `generatePath()` ([#15277](https://github.com/remix-run/react-router/pull/15277)) - splat params preserve path separators while encoding each segment individually - Fix dynamic param extraction for routes with optional static segments ([#15200](https://github.com/remix-run/react-router/pull/15200)) - When a route path contains optional static segments (e.g. `/school?/user/:id`), the internal regex's incorrectly shifted parameter indices resulting in incorrect parameter extraction - Consecutive optional static segments (e.g. `/one?/two?`) were only partially handled - Preserve navigation blocker state through a revalidation ([#15246](https://github.com/remix-run/react-router/pull/15246)) - Fix route ranking for dynamic parameters with static extension suffixes ([#15273](https://github.com/remix-run/react-router/pull/15273)) - These were not being detected as dynamic param segments and instead got incorrectly scored higher as a static segment - This meant they could potentially tie truly static routes like `/sitemap.xml` and outrank them based on definition order - These are now correctly identified as dynamic parameter segments and scored correctly - Use ReactFormState types instead of unknown ([#15263](https://github.com/remix-run/react-router/pull/15263)) ## v8.1.0 ### Minor Changes - Return route metadata from server request, client navigation, and client fetcher instrumentations ([#15235](https://github.com/remix-run/react-router/pull/15235)) - Adds result metadata after instrumented calls complete, including the URL, matched route pattern, and params - Adds known HTTP status codes to server request handler instrumentation results ## v8.0.1 ### Patch Changes - Remove the obsolete `AppLoadContext` type export accidentally left over from v7 now that middleware is always enabled and server request context is provided through `RouterContextProvider`. ([#15207](https://github.com/remix-run/react-router/pull/15207)) ## v8.0.0 ### Major Changes - Remove the `future.v8_trailingSlashAwareDataRequests` flag ([#15100](https://github.com/remix-run/react-router/pull/15100)) - Trailing slash-aware data request URLs are now the default behavior. - Update `tsconfig.json` `target`/`lib` from `ES2020 -> ES2022` ([591853e](https://github.com/remix-run/react-router/commit/591853e)) - Switch the published packages in `packages/` to ESM-only. ([#14895](https://github.com/remix-run/react-router/pull/14895)) ([59ebcf1](https://github.com/remix-run/react-router/commit/59ebcf1)) - Remove deprecated `data` parameter in favor of `loaderData` for `meta` APIs (to align with `Route.ComponentProps`) ([#14931](https://github.com/remix-run/react-router/pull/14931)) - `Route.MetaArgs`, `Route.MetaMatch`, `MetaArgs`, `MetaMatch`, `Route.ComponentProps.matches`, `UIMatch` - Remove `future.v8_passThroughRequests` flag - the raw incoming `request` is now always passed through to `loader`/`action`. Use `url` for the normalized URL without React Router-specific implementation details (`.data` suffixes, `index`/`_routes` search params). ([#15079](https://github.com/remix-run/react-router/pull/15079)) - Remove internal `hasErrorBoundary` field added to `router.routes` when using a data router ([#15074](https://github.com/remix-run/react-router/pull/15074)) - This should not impact user-facing code since this was an internal prop and was computed based on the presence of `ErrorBoundary` or `errorElement` on your route - `hasErrorBoundary` is no longer accepted on `RouteObject` (`IndexRouteObject`/`NonIndexRouteObject`), `DataRouteObject`, `` JSX props, or as a key in `lazy` route definitions. - The `MapRoutePropertiesFunction` signature no longer requires returning `hasErrorBoundary`; the router infers it directly. - Remove `react-router-dom` package ([#15076](https://github.com/remix-run/react-router/pull/15076)) - In v7 everything DOM-specific was collapsed into `react-router/dom` - `react-router-dom` was kept around as a convenience so existing v6 app imports would still work - For v8, you will need to swap `react-router-dom` imports: - `RouterProvider`/`HydratedRouter` should be imported from `react-router/dom` - Everything else should be imported from `react-router` - Remove `future.v8_middleware` flag — middleware is always enabled in v8 ([#15078](https://github.com/remix-run/react-router/pull/15078)) - The `future.v8_middleware` flag has been removed; middleware is now always enabled - The `context` parameter passed to `loader`, `action`, and `middleware` functions is always a `RouterContextProvider` instance - `getLoadContext` functions in custom servers must return a `RouterContextProvider` — returning a plain object is no longer supported - The `MiddlewareEnabled` type (previously exported as `UNSAFE_MiddlewareEnabled`) has been removed since the conditional it gated is now unconditional - The `Future` module augmentation pattern (`interface Future { v8_middleware: true }`) is no longer needed to type `context` in Data Mode - Update minimum Node version to 22.22.0 ([#14928](https://github.com/remix-run/react-router/pull/14928)) - Update minimum React version to 19.2.7 ([#15062](https://github.com/remix-run/react-router/pull/15062)) ### Minor Changes - Bump dependencies ([#15080](https://github.com/remix-run/react-router/pull/15080)) - Bumped `cookie` from `^1.0.1` to `^1.1.1` - Bumped `set-cookie-parser` from `^2.6.0` to `^3.1.0` ### Patch Changes - Ensure client middleware errors load lazy route error boundaries before bubbling ([#15086](https://github.com/remix-run/react-router/pull/15086)) - Remove explicit `onSubmit` type override from `SharedFormProps` to fix deprecation warning with `@types/react@19.x` ([#14932](https://github.com/remix-run/react-router/pull/14932)) ([59ebcf1](https://github.com/remix-run/react-router/commit/59ebcf1)) - Update package builds to preserve individual module files in published artifacts. Public APIs and documented import paths are unchanged. ([#15092](https://github.com/remix-run/react-router/pull/15092)) - Updated package TypeScript configs to support modern module syntax used by the build configuration. - Migrate package builds from `tsup` to `tsdown`. Published package entry points and public APIs are unchanged. ([#15092](https://github.com/remix-run/react-router/pull/15092)) - Upgrade React Router's TypeScript tooling to TypeScript 6. Runtime behavior and public APIs are unchanged. ([#15092](https://github.com/remix-run/react-router/pull/15092)) ## v7.18.0 ### Patch Changes - Fix server handler prerender responses when using `ssr: false` and `future.v8_trailingSlashAwareDataRequests: true`. Avoids false positive "SPA Mode" detection when serving prerendered paths ([#15173](https://github.com/remix-run/react-router/pull/15173)) - Use the `ServerRouter` nonce for nonce-aware SSR components when they don't provide their own value so strict CSP pages can load them. ([#15170](https://github.com/remix-run/react-router/pull/15170)) - Use `turbo-stream` to serialize and deserialize Framework Mode hydration errors ([#15175](https://github.com/remix-run/react-router/pull/15175)) - Precompute route branch matchers to avoid recompiling route path regexes during matching ([#15186](https://github.com/remix-run/react-router/pull/15186)) - Use the constructed request URL host when validating action request origins. ([#15185](https://github.com/remix-run/react-router/pull/15185)) - Remove the un-documented custom error serialization logic from Data Mode SSR built-in hydration flows ([#15175](https://github.com/remix-run/react-router/pull/15175)) - Validate protocols in RSC render redirects ([#15177](https://github.com/remix-run/react-router/pull/15177)) - Consolidate url normalization logic and better handle mixed slashes ([#15176](https://github.com/remix-run/react-router/pull/15176)) ## v7.17.0 ### Minor Changes - Ship a subset of the official documentation inside the `react-router` package ([#15121](https://github.com/remix-run/react-router/pull/15121)) - Markdown docs are now available in `node_modules/react-router/docs`, letting AI coding agents and the React Router agent skills read official docs locally - Excludes auto-generated API docs (`api/`), `community/` content, and tutorials (`tutorials/`) ## v7.16.0 ### Minor Changes - Stabilize `future.unstable_trailingSlashAwareDataRequests` as `future.v8_trailingSlashAwareDataRequests` ([#15098](https://github.com/remix-run/react-router/pull/15098)) ### Patch Changes - Disable manifest path when lazy route dicovery is disabled ([#15068](https://github.com/remix-run/react-router/pull/15068)) - Fix browser URL creation to use the configured history window instead of the global window. ([#15066](https://github.com/remix-run/react-router/pull/15066)) - Pass the history/router window through to `createBrowserURLImpl` so custom window contexts keep the correct URL origin. - Fix `useNavigation()` return type to preserve discriminated union across navigation states ([#15095](https://github.com/remix-run/react-router/pull/15095)) - Widen `MetaDescriptor` `script:ld+json` type from `LdJsonObject` to `LdJsonObject | LdJsonObject[]` to permit multiple JSON-LD schemas in a single `