---
title: "React Router v8 Graduates Its Future Flags to Defaults, Goes ESM-Only, and Drops `react-router-dom`"
description: "React Router v8.0.0 (June 17, 2026) is the first major release under the project's Open Governance model and the first on a planned yearly cadence. Every `future.v8_*` flag from v7 is now the default (always-on middleware, pass-through requests, the Vite Environment API, route-module splitting), the baseline moves to Node 22.22+, React 19.2.7+, and Vite 7+, all packages ship ESM-only with an ES2022 target, `react-router-dom` is removed, and the node adapters switch to a Remix-maintained fetch server while `create-react-router` drops its fetch polyfill for native `fetch`."
date: 2026-06-19
image: "/images/heroes/2026-06-19--react-router-v8-major-release-future-flags-esm.png"
author: lschvn
tags: ["frameworks", "tooling", "typescript"]
tldr:
  - "React Router v8.0.0 shipped June 17, 2026, with a follow-up v8.0.1 patch on June 18. It is the first major release under the project's Open Governance model and the first on a planned yearly cadence, timed to the Node 20 end-of-life window and aiming v9 at roughly May 2027 alongside the Node 22 EOL. The API Development Strategy graduates every `future.v8_*` flag to a default, so apps that adopted the flags in v7 see almost no API change."
  - "The baseline jumps to Node 22.22.0+, React 19.2.7+, and Vite 7+. Every published package is now ESM-only with the tsconfig `target`/`lib` moved from ES2020 to ES2022. `react-router-dom` is removed (import from `react-router` and `react-router/dom`), the deprecated `meta` `data` fields are gone in favor of `loaderData`, and the Cloudflare dev proxy and the internal `hasErrorBoundary` field are dropped."
  - "Middleware is now always on, which means `context` is always a `RouterContextProvider` and `getLoadContext` must return one rather than a plain object. The node and serve adapters switch from `@mjackson/node-fetch-server` to `@remix-run/node-fetch-server`, and `create-react-router` replaces `@remix-run/web-fetch` with native `fetch`, which quietly removes `HTTPS_PROXY` support. The package build moved from `tsup` to `tsdown` on TypeScript 6."
faq:
  - question: "Is upgrading to React Router v8 a breaking change?"
    answer: "Only if you skipped the v7 future flags. React Router's API Development Strategy ships breaking changes behind `future.v8_*` flags first, so apps that adopted all active flags in v7 see almost no API-surface change in v8, because those flags are now removed (or lifted to top-level config) and their behavior is the default. The unconditional breaks are the baseline bumps (Node 22.22+, React 19.2.7+, Vite 7+), the removal of `react-router-dom`, the removal of the deprecated `meta` `data` fields in favor of `loaderData`, and the always-on middleware contract where `getLoadContext` must return a `RouterContextProvider` instead of a plain object."
  - question: "Why does React Router v8 require Node 22.22, React 19.2.7, and Vite 7?"
    answer: "v8 sets a new baseline policy: it supports all Active LTS Node versions plus only the latest minor branch of Maintenance LTS, which lets the project adopt Active LTS features that are backported and bump the Maintenance LTS floor quickly when a security patch lands. Node 22.22+ is that floor for the launch, timed to the Node 20 end-of-life window; the project plans v9 around May 2027 to track the Node 22 EOL. React 19.2.7+ and Vite 7+ are required because v8 unconditionally uses the Vite Environment API (previously a flag) and targets modern React."
  - question: "What happened to `react-router-dom` in v8?"
    answer: "It is removed. In v7 the DOM APIs were collapsed into `react-router/dom`, and `react-router-dom` was kept only as a re-export shim to ease the v6-to-v7 migration. In v8 the shim is gone, so any remaining `react-router-dom` imports must move: `RouterProvider` and `HydratedRouter` come from `react-router/dom`, and everything else comes from `react-router`."
  - question: "Is React Router v8 ESM-only?"
    answer: "Yes. The published packages under `packages/` were switched to ESM-only, and the tsconfig `target`/`lib` fields were moved from ES2020 to ES2022 across the board. Being ESM-only is also what enabled the adapter rewrites: `@react-router/node` and `@react-router/serve` could drop `@mjackson/node-fetch-server` for `@remix-run/node-fetch-server`, and `create-react-router` could drop `@remix-run/web-fetch` for Node's native `fetch`."
  - question: "What does it mean that middleware is always on in v8?"
    answer: "The `future.v8_middleware` flag is removed and middleware runs unconditionally. The `context` passed to `loader`, `action`, and `middleware` is always a `RouterContextProvider` instance, so `getLoadContext` in a custom server must return a `RouterContextProvider` rather than a plain object. The `MiddlewareEnabled` type (previously `UNSAFE_MiddlewareEnabled`) and the `interface Future { v8_middleware: true }` module-augmentation trick for typing `context` in Data Mode are no longer needed."
---

[React Router v8.0.0](https://github.com/remix-run/react-router/releases/tag/react-router%408.0.0) shipped on June 17, 2026, followed by a v8.0.1 patch the next day. It is the first major release under the project's [Open Governance](https://remix.run/blog/rr-governance) model and the first on a planned yearly cadence, deliberately timed to the Node 20 end-of-life window. Node 22 itself is [scheduled](https://nodejs.org/en/about/previous-releases) to reach EOL around May 2027, which is where the team is pointing v9. The headline is less a single feature and more a graduation: the API Development Strategy's job is to make major releases boring by landing breaking changes early behind [Future Flags](https://reactrouter.com/upgrading/v7), and v8 is the release where every `future.v8_*` flag from v7 becomes the default.

## Future flags graduate to defaults

If you adopted all active future flags in v7, the v8 API surface is largely unchanged, because those flags are removed or lifted to top-level config and their behavior is now unconditional. The flags that graduated:

- `future.v8_trailingSlashAwareDataRequests` is gone; trailing-slash-aware data request URLs are the default.
- `future.v8_passThroughRequests` is gone; the raw incoming `request` is now always passed through to `loader` and `action`. Use the `url` parameter when you want the normalized URL without React Router internals like `.data` suffixes and `_routes` search params.
- `future.v8_middleware` is gone; middleware always runs. The `context` passed to loaders, actions, and middleware is always a `RouterContextProvider`, `getLoadContext` in a custom server must return one rather than a plain object, the `MiddlewareEnabled` type is removed, and the `interface Future { v8_middleware: true }` augmentation trick is no longer needed to type `context` in Data Mode.
- `future.v8_viteEnvironmentApi` is gone; the Vite Environment API build path is mandatory, which is why v8 requires [Vite 7+](/articles/2026-06-15--vite-8-1-beta-wasm-esm-chunk-importmap) and why the old pre-rendering implementation was replaced by the Vite preview-server flow.
- `future.v8_splitRouteModules` moved to a top-level `splitRouteModules` config option and defaults to `true`. Set it to `false` to keep route modules in a single chunk, or `"enforce"` to require every route to be splittable.

The "graduation" framing is the real story. Future flags let the team land a breaking change in a v7 minor, let users opt in and report back, and then flip the default in the major with a year of production validation behind it. v8 is the payoff release for that pipeline.

## New baselines: Node 22.22, React 19.2.7, Vite 7, and ESM-only

v8 sets a new baseline policy that is worth reading closely. React Router now officially supports all Active LTS Node versions and only the latest minor branch of Maintenance LTS, so it can bump the Maintenance LTS floor quickly when a security patch lands (as it did in the [June 2026 Node.js security releases](/articles/2026-06-18--node-js-june-2026-security-releases)) and adopt Active LTS features that get backported. For the launch that floor is Node 22.22.0+, alongside React 19.2.7+ and Vite 7+.

To modernize the library, every published package is now ESM-only and the tsconfig `target`/`lib` fields moved from ES2020 to ES2022 across the board. That ESM-only decision is not cosmetic: it is what unlocked the adapter rewrites below, because the adapters could finally consume other ESM-only packages directly.

## `react-router-dom` is gone, and so are a few deprecated APIs

The most visible removal is [`react-router-dom`](https://github.com/remix-run/react-router/pull/15076). In v7 the DOM APIs were collapsed into `react-router/dom`, and `react-router-dom` was kept only as a re-export shim so existing v6 imports kept working. The shim is gone in v8. Any remaining `react-router-dom` imports must move: `RouterProvider` and `HydratedRouter` come from `react-router/dom`, everything else from `react-router`.

Three more removals round out the list. The deprecated `data` fields passed to route-module `meta` functions are gone; use `loaderData` instead on `MetaArgs` and each item in `MetaArgs.matches` ([#14931](https://github.com/remix-run/react-router/pull/14931)). The Cloudflare dev proxy at `@react-router/dev/vite/cloudflare` is removed in favor of [`@cloudflare/vite-plugin`](https://developers.cloudflare.com/workers/vite-plugin/), which also drops `wrangler@3` as a peer dependency of `@react-router/dev`. And the internal `hasErrorBoundary` field that was injected onto `router.routes` is gone; the router now infers error boundaries directly, and `hasErrorBoundary` is no longer accepted on `RouteObject`, `DataRouteObject`, the `<Route>` JSX props, or `lazy` route definitions ([#15074](https://github.com/remix-run/react-router/pull/15074)).

## Adapter internals: native fetch, node-fetch-server, tsdown, TypeScript 6

The adapter layer got a quiet rewrite that matters for anyone running React Router on Node or generating apps with `create-react-router`. `@react-router/node` and `@react-router/serve` switch from `@mjackson/node-fetch-server` to `@remix-run/node-fetch-server`, and `create-react-router` replaces `@remix-run/web-fetch` with Node's native `fetch`. The practical side effect: `create-react-router` no longer supports the `HTTPS_PROXY` environment variable that the old `node-fetch`-based polyfill honored ([#14929](https://github.com/remix-run/react-router/pull/14929)), which is worth knowing if your CI sits behind a corporate proxy.

On the build side, the package build migrated from `tsup` to `tsdown` and the TypeScript tooling moved to TypeScript 6, while preserving individual module files in the published artifacts so public APIs and documented import paths are unchanged ([#15092](https://github.com/remix-run/react-router/pull/15092)). `@react-router/dev` replaced `cookie` and `set-cookie-parser` with `cookie-es`, removed the `vite-node` dependency in favor of Vite's native module runner APIs, and bumped a long tail of dependencies (Babel to 7.29, `react-refresh` to 0.18, `es-module-lexer` to 2.1, `chokidar` to 5). The Express adapter now requires Express `^4.22.2 || ^5`, and `@react-router/serve` moved to Express 5.2.1.

## The upgrade path

For most teams the upgrade is mechanical if v7's future flags were already on. The work is: bump Node to 22.22+, React to 19.2.7+, and Vite to 7+; swap any lingering `react-router-dom` imports; rename `data` to `loaderData` in `meta` functions; and make sure `getLoadContext` returns a `RouterContextProvider`. The v7.18.0 release on June 16 also shipped a [CSRF check logic fix](https://github.com/remix-run/react-router/releases/tag/react-router%407.18.0) that is a potential "breaking bug fix" behind a reverse proxy: the check now reads the `host` from the request URL rather than HTTP headers, so `@react-router/serve` or `@react-router/express` apps without `trust proxy` enabled may need to add the internal host to `allowedActionOrigins`. Test mutation requests as part of the upgrade.

v8.0.1 (June 18) is a single cleanup patch that removes the obsolete `AppLoadContext` type export left over from v7, now that request context always flows through `RouterContextProvider` ([#15207](https://github.com/remix-run/react-router/pull/15207)). It lands a day after the major, which itself lands the same week [vue-router hit its v5 line](/articles/2026-04-06--nuxt-4-4-vue-router-v5-typed-layout-props-28x-faster-dev-routing). The yearly cadence and the future-flag pipeline mean the next major should look a lot like this one: most of the breaks will already have shipped in a v8 minor, and v9 will mostly flip the defaults.
