new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

React Router · Guides · all subjects

architecture

128 notes in this subject, read out of this brain and free to use. This is page 2 of 3.

Presets option in React Router config

The React Router config supports a presets option to ease integration with other tools and hosting providers.

What presets can do

Presets can only do two things: configure React Router config options on your behalf, and validate the resolved config.

Preset config merge order

The config returned by each preset is merged in the order the presets were defined. Any config directly specified in your React Router config will be merged last, which means your config will always take precedence over any presets.

Using a preset in react-router.config.ts

Import a preset and include it in the presets array of your React Router config: ```ts import type { Config } from "@react-router/dev/config"; import { myCoolPreset } from "react-router-preset-cool"; export default { // ... presets: [myCoolPreset()], } satisfies Config; ```

Validating preset config with reactRouterConfigResolved

Use the reactRouterConfigResolved hook to validate that the final resolved config contains expected values from your preset. This hook should only be used when it would be an error to merge or override your preset's config. Example: ```ts reactRouterConfigResolved: ({ reactRouterConfig }) => { if (reactRouterConfig.serverBundles !== serverBundles) { throw new Error("`serverBundles` was overridden!"); } } ```

Creating a preset with serverBundles

Example preset implementation: ```ts import type { Preset } from "@react-router/dev/config"; export function myCoolPreset(): Preset { return { name: "my-cool-preset", reactRouterConfig: () => ({ serverBundles: ({ branch }) => { const isAuthenticatedRoute = branch.some((route) => route.id.split("/").includes("_authenticated"), ); return isAuthenticatedRoute ? "authenticated" : "unauthenticated"; }, }), }; } ``` This preset configures a serverBundles function that returns a string identifying which bundle to use based on whether the route is in the '_authenticated' segment.

Preset type structure

A Preset object has a name property (string) and can have a reactRouterConfig function that returns partial React Router config, and/or a reactRouterConfigResolved hook that receives the final resolved config for validation.

Content Security Policy nonce for RSC hydration

A Content Security Policy can use a per-response nonce to allow inline scripts required for RSC hydration without allowing arbitrary inline scripts. Generate a fresh nonce for each document response and pass it to routeRSCServerRequest, RSCStaticRouter, and the CSP response header. In Framework Mode, run 'react-router reveal entry.ssr' first.

React Server Components (RSC) support is experimental

React Server Components support in React Router is experimental and subject to breaking changes in minor and patch releases. Users should use with caution and pay very close attention to release notes for relevant changes.

RSC available in Framework and Data Modes

React Router provides RSC support in both Framework Mode and Data Mode. The APIs and features differ between RSC and non-RSC modes.

RSC Framework Mode quick start template

The RSC Framework Mode template uses the unstable React Router RSC Vite plugin along with the experimental @vitejs/plugin-rsc plugin. Install with: npx create-react-router@latest --template remix-run/react-router-templates/unstable_rsc-framework-mode

RSC Data Mode quick start template

The Vite RSC Data Mode template uses the experimental Vite @vitejs/plugin-rsc plugin. Install with: npx create-react-router@latest --template remix-run/react-router-templates/unstable_rsc-data-mode-vite

RSC Framework Mode Vite plugin configuration

RSC Framework Mode uses the unstable_reactRouterRSC Vite plugin, which has a peer dependency on @vitejs/plugin-rsc. The @vitejs/plugin-rsc plugin must be placed after the React Router RSC plugin in the Vite config. Example: plugins: [reactRouterRSC(), rsc()]

RSC Framework Mode build output structure

The RSC Framework Mode server build file (build/server/index.js) exports a default request handler function with signature (request: Request) => Promise<Response> for document and data requests. It can be converted to a standard Node.js request listener using createRequestListener from @remix-run/node-fetch-server.

.server and .client modules not built-in with RSC Framework Mode

Support for .server modules and .client modules is no longer built-in when using RSC Framework Mode to avoid confusion with RSC's "use server" and "use client" directives. Instead, use "server-only" and "client-only" imports provided by @vitejs/plugin-rsc as side effects in modules to ensure build-time validation.

Custom entry files in RSC Framework Mode

RSC Framework Mode supports custom entry files that can customize RSC server, SSR server, and client entry points. The plugin automatically detects: app/entry.rsc.ts/tsx (custom RSC server entry), app/entry.ssr.ts/tsx (custom SSR server entry), app/entry.client.tsx (custom client entry). Use 'react-router reveal' commands to inspect generated defaults.

Custom RSC entry file requirements

Custom RSC entry files (entry.rsc.ts) must export a default object with a fetch method. Custom SSR entry files (entry.ssr.ts) must export a generateHTML function. Custom client entry files (entry.client.tsx) should handle client-side hydration.

Unsupported config options in RSC Framework Mode

The following react-router.config.ts options are not currently supported in RSC Framework Mode: buildEnd, presets, serverBundles, splitRouteModules.

RSC Data Mode entry points overview

RSC Data Mode requires three entry points: (1) entry.ssr.tsx for server to handle requests, fetch RSC payload, and convert to HTML; (2) entry.rsc.tsx for React Server to generate RSC payloads; (3) entry.browser.tsx for client to hydrate HTML and set callServer function for post-hydration server actions.

Vite RSC Data Mode configuration

For Vite RSC Data Mode, add @vitejs/plugin-react and @vitejs/plugin-rsc to vite.config.ts with rsc plugin configuration specifying entry points: client: "src/entry.browser.tsx", rsc: "src/entry.rsc.tsx", ssr: "src/entry.ssr.tsx"

Express server setup with RSC Framework Mode build

RSC Framework Mode build output (build/server/index.js) exports a request handler that can be used with Express. Import the handler and convert it using createRequestListener from @remix-run/node-fetch-server, then use it as middleware after serving static assets.

buildEnd hook receives buildManifest

When the build is complete, React Router calls the buildEnd hook and passes a buildManifest object. This is useful if you need to inspect the build manifest to determine how to route requests to the correct server bundle.

buildManifest object structure for server bundles

When using server bundles, the buildManifest object passed to the buildEnd hook contains the following properties: serverBundles (an object that maps bundle IDs to the bundle's id and file), routeIdToServerBundleId (an object that maps route IDs to their server bundle ID), and routes (a route manifest that maps route IDs to route metadata, which can be used to drive a custom routing layer in front of your React Router request handlers).

Server Bundles overview and purpose

React Router typically builds server code into a single bundle that exports a request handler function. However, you can split the route tree into multiple server bundles, each exposing a request handler function for a subset of routes. This is an advanced feature designed for hosting provider integrations, and when compiling your app into multiple server bundles, there will need to be a custom routing layer in front of your app directing requests to the correct bundle.

serverBundles configuration option

The serverBundles option in react-router.config.ts is a function that is called for each route in the tree (except for routes that aren't addressable, such as pathless layout routes) and returns a server bundle ID to assign that route to. These bundle IDs will be used as directory names in the server build directory.

serverBundles function receives route branch

The serverBundles function receives an array of routes leading to and including the current route, referred to as the route branch. This allows you to create server bundles for different portions of the route tree, such as a separate server bundle containing all routes within a particular layout route.

Route properties in serverBundles branch

Each route in the branch array passed to serverBundles contains the following properties: id (the unique ID for this route, named like its file but relative to the app directory and without the extension, e.g., app/routes/gists.$username.tsx will have an id of routes/gists.$username), path (the path this route uses to match the URL pathname), file (the absolute path to the entry point for this route), and index (whether this route is an index route).

serverBundles example splitting authenticated and unauthenticated routes

This example shows how to use serverBundles to split routes into 'authenticated' and 'unauthenticated' bundles based on whether the route's id includes '_authenticated': ```ts import type { Config } from "@react-router/dev/config"; export default { serverBundles: ({ branch }) => { const isAuthenticatedRoute = branch.some((route) => route.id.split("/").includes("_authenticated"), ); return isAuthenticatedRoute ? "authenticated" : "unauthenticated"; }, } satisfies Config; ```

future.unstable_enableNodeReadableStream flag purpose

The future.unstable_enableNodeReadableStream flag enables React Router to use React's renderToReadableStream on all runtimes including Node, now that the Web Streams API is stable in Node 22+. This can provide slight performance gains because Web Streams are already used internally, removing unnecessary transforms between Web and Node streams. By default, React Router uses renderToPipeableStream on Node runtime and renderToReadableStream on other runtimes.

Enable future.unstable_enableNodeReadableStream flag

Enable the future.unstable_enableNodeReadableStream flag in react-router.config.ts using: export default { future: { unstable_enableNodeReadableStream: true } } satisfies Config;

No code changes needed for future.unstable_enableNodeReadableStream

Enabling the future.unstable_enableNodeReadableStream flag requires no code changes. If your app has a custom entry.server.tsx file, this flag will not change your runtime behavior.

future.unstable_optimizeDeps flag purpose

The future.unstable_optimizeDeps flag allows React Router to provide Vite's dependency optimizer with the client entry file and route module files. This can improve dependency optimization in development, though the behavior is still experimental.

Enable future.unstable_optimizeDeps flag

Enable the future.unstable_optimizeDeps flag in react-router.config.ts using: export default { future: { unstable_optimizeDeps: true } } satisfies Config;

Troubleshooting future.unstable_optimizeDeps flag

If you run into dependency optimization issues after enabling the future.unstable_optimizeDeps flag, remove the flag and restart the dev server.

Unstable flags warning

Unstable flags are documented as a reference for folks contributing to the project via beta testing but are not generally recommended for production use. They may have breaking changes in patch or minor releases and should be adopted with caution.

Framework adoption guide for component routes applies to <Routes>

This upgrade guide applies only to apps currently using <Routes>. If using <RouterProvider>, see the separate Framework Adoption from RouterProvider guide.

Move index.html to root.tsx

React Router Vite plugin uses root.tsx as the app shell entry point instead of index.html. Move your index.html markup into src/root.tsx and delete index.html. The root.tsx file should export a Layout component that wraps children with html tags and includes Meta, Links, ScrollRestoration, and Scripts components from react-router, plus a default export Root component that renders Outlet.

Root.tsx Layout component structure

The Layout component in root.tsx receives children as a prop and wraps them in html tags. The head should include Meta and Links components from react-router. The body should include children, ScrollRestoration, and Scripts components.

Client entry point migration from main.tsx to entry.client.tsx

Rename src/main.tsx to src/entry.client.tsx. Replace ReactDOM.createRoot with ReactDOM.hydrateRoot, replace BrowserRouter with HydratedRouter imported from react-router/dom, and remove rendering of your App component initially.

Root.tsx must be server-rendering compatible

The root.tsx file will be statically generated and served as the entry point of the app, so this module must be compatible with server rendering. This is typically where migration issues occur.

Development script setup

Add "dev": "react-router dev" to the scripts section in package.json to start the development server.

Ignore .react-router generated directory

Add .react-router/ to .gitignore to avoid tracking automatically generated files in the repository.

Entry point shuffle considerations

Between root.tsx and entry.client.tsx, decide what belongs where: root.tsx contains rendering things like context providers, layouts, and styles; entry.client.tsx should be as minimal as possible. Do not try to render the App component in entry.client.tsx during initial setup.

React Router Vite plugin prerequisites

To use the React Router Vite plugin, your project requires Node.js 22.22.0 or higher and Vite 7 or Vite 8.

React Router Vite plugin features

The React Router Vite plugin adds route loaders, actions, and automatic data revalidation; type-safe route modules; automatic route code-splitting; automatic scroll restoration across navigations; optional static pre-rendering; and optional server rendering.

Install React Router Vite plugin packages

Install @react-router/dev as a dev dependency with npm install -D @react-router/dev. For Node runtime, also install @react-router/node as a regular dependency.

Replace Vite React plugin with React Router plugin

In vite.config.ts, replace the @vitejs/plugin-react import and react() plugin with an import of reactRouter from @react-router/dev/vite and add reactRouter() to the plugins array.

React Router configuration file

Create a react-router.config.ts file at the project root with type Config from @react-router/dev/config. Specify appDirectory (e.g., "src") and set ssr: false initially to disable server-side rendering.

Root entry point replaces index.html

The React Router Vite plugin uses src/root.tsx as the entry point instead of index.html. Move HTML markup from index.html into src/root.tsx and use React components: export a Layout component that returns the HTML structure with children, and export a default Root component that renders Outlet. Import Links, Meta, Outlet, Scripts, and ScrollRestoration from react-router.

Move global styles and providers to root.tsx

Any global styles, context providers, or other components that should be shared across all routes should be moved from App.tsx into the root.tsx Root component, wrapping the Outlet.

Dev script for React Router Vite plugin

Add "dev": "react-router dev" to the scripts section of package.json to run the development server.

Ignore generated React Router files

Add .react-router/ to .gitignore to avoid tracking files generated by the React Router Vite plugin.

Enable SSR and pre-rendering in React Router config

To enable server-side rendering and static pre-rendering, set ssr: true and add an async prerender() function that returns an array of paths to pre-render in react-router.config.ts. For SSR, the server build must be deployed to a server.

Root component example with Layout

Example root.tsx: ```tsx import { Links, Meta, Outlet, Scripts, ScrollRestoration, } from "react-router"; export function Layout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <head> <meta charSet="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>My App</title> <Meta /> <Links /> </head> <body> {children} <ScrollRestoration /> <Scripts /> </body> </html> ); } export default function Root() { return <Outlet />; } ```

Import from react-router instead of react-router-dom

In v8, import most APIs from react-router package. For DOM-specific APIs like RouterProvider, import from react-router/dom. Example: import { Link, useLocation } from 'react-router'; import { RouterProvider } from 'react-router/dom';

Replace cloudflareDevProxy with @cloudflare/vite-plugin

React Router v8 removes the React Router Cloudflare dev proxy. Cloudflare projects should use @cloudflare/vite-plugin instead. Replace cloudflareDevProxy() with cloudflare() in vite.config.ts and remove the @react-router/dev/vite/cloudflare import.

Update @react-router/architect adapter for v8

In v8, @react-router/architect adapter uses event.requestContext.domainName by default instead of X-Forwarded-Host header. In v7, opt in to v8 behavior by passing useRequestContextDomainName: true to createRequestHandler. This option is removed in v8 as the domainName behavior is the default.

Upgrade to React Router v8

After adopting future flags and making code updates on v7, upgrade with: For data/declarative mode: npm install react-router@latest. For framework mode: npm install react-router@latest @react-router/{dev,node,etc.}@latest

React Router v8 minimum versions

React Router v8 requires node@22.22+, react@19.2.7+, and react-dom@19.2.7+. Framework mode also requires vite@7+ with future.v8_viteEnvironmentApi flag enabled, and all custom Vite plugins or config must be compatible with Vite 7.

Update to latest v7.x before upgrading to v8

Before adopting any future flags or call-site opt-in changes, update to the latest minor version of v7.x to ensure access to the latest flags. Run: npm install react-router@7 @react-router/{dev,node,etc.}@7

Give your agent this brain