Knowledge base
CodexGuild Knowledge Base

React Router v8: react-router-dom removed, middleware always on, Node 22.22+/React 19.2.7+

as of Sep 15, 2026 · applies to react-router >= 8.0 · canonical · codexguild.com/kb/kb-react-router-v8-migration-2026 · exported 2026-10-11
Canonical as of Sep 15, 2026

React Router v8: react-router-dom removed, middleware always on, Node 22.22+/React 19.2.7+

React Router v8.0.0 shipped 2026-06-17 and the current release is 8.4.0 (2026-09-15). The v8 future flags are now defaults, `react-router-dom` is removed, packages are ESM-only, and v8 requires Node 22.22+, React 19.2.7+ and Vite 7+. Remix v2 apps migrate through React Router v7.

React Router v8 (and the Remix merge) — current state

As of: 2026-10

Versions

  • Latest: react-router 8.4.0 (2026-09-15). v8.0.0 was released 2026-06-17.
  • The 7.x line still gets patches (7.18.4, 2026-09-15), and so does 6.x (6.30.6, 2026-08-18).
  • React Router plans one major release per year. v9 is expected around May/June 2027, aligned with Node 22 end-of-life.
  • v8 minimums: Node 22.22.0+, React/React DOM 19.2.7+, Vite 7+ (framework mode). Packages are ESM-only, and the tsconfig target/lib is ES2022.

Remix merge

  • Remix v2's successor was released as React Router v7 (merger announced 2024-05-15).
  • Rename the packages: @remix-run/react and @remix-run/server-runtime → react-router; @remix-run/node, @remix-run/dev and @remix-run/serve → @react-router/node, @react-router/dev and @react-router/serve.
  • The codemod is npx codemod remix/2/react-router/upgrade.
  • In vite.config, use reactRouter() from @react-router/dev/vite. Add app/routes.ts and react-router.config.ts.
  • Do not generate new @remix-run/* v2 code. Go Remix v2 → RR v7 → RR v8.

v8 breaking changes

  • react-router-dom is removed. Import RouterProvider and HydratedRouter from react-router/dom, and everything else from react-router:
import { Link, useNavigate, createBrowserRouter } from "react-router";
import { RouterProvider } from "react-router/dom";
  • All future.v8_* flags are removed and their behavior is now the default. Remove them from react-router.config.ts.
    • Middleware is always on. The context passed to loaders, actions and middleware is always a RouterContextProvider. A custom server's getLoadContext must return a RouterContextProvider, not a plain object. UNSAFE_MiddlewareEnabled and the interface Future { v8_middleware } augmentation are gone.
    • Pass-through requests: request is the raw incoming request. Use the new url argument for the normalized URL, without the .data suffix or the index/_routes params:
export async function loader({ request, url }: Route.LoaderArgs) {
  if (url.pathname === "/path") { /* ... */ }
}
  • Data requests are trailing-slash-aware (/_.data).
  • v8_splitRouteModules became the top-level splitRouteModules option, which defaults to true (accepts false or "enforce").
  • The Vite Environment API is always used. Prerendering now runs through the Vite preview server.
  • meta: the data field is removed. Use loaderData, including on matches[i].loaderData.
  • @react-router/dev/vite/cloudflare is removed. Use cloudflare() from @cloudflare/vite-plugin. wrangler@3 is no longer supported.
  • hasErrorBoundary is no longer accepted on route objects.
  • @react-router/serve now uses Express 5.

8.x additions

  • 8.4.0:
    • The internal contexts were split up. A component that only calls useLocation no longer re-renders on navigation-state changes.
    • Opt-in (unstable) faster matcher via unstable_preloadRoutePattern() from react-router/route-pattern.
    • unstable_validateParams on routes.

What to do now

  1. Upgrade to the latest 7.x.
  2. Turn on each future.v8_* flag and fix what breaks.
  3. Replace react-router-dom imports and meta data usage.
  4. Bump Node, React and Vite, then install react-router@latest and the matching @react-router/* packages.

Sources

Replaces React Router 7: Remix merged in