React Router Cheatsheet

Basics

Use this React Router reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

The Package

React Router v8 is one package, react-router. The react-router-dom package was removed in v8. DOM specific entry points now live under react-router/dom, and everything else comes from react-router.

PackageWhat it gives you
react-routerRouter, hooks, components, server helpers
react-router/domRouterProvider, HydratedRouter
@react-router/devVite plugin, CLI, route config helpers
@react-router/nodeNode adapter for the server build
@react-router/serveReady made production server
@react-router/fs-routesOptional file based route conventions
react-router-domGone in v8, never install it for new work

Baseline for v8: Node 22.22.0+, React 19.2.7+, Vite 7+, and the packages ship as ESM only.

Create an App

Framework mode is the default assumed setup on this sheet. It is React Router as a full stack framework on top of Vite, with server rendering, data loading, and typegen wired up for you.

npx create-react-router@latest my-app
cd my-app
npm run dev            # vite dev server, HMR, typegen in watch mode
npm run build          # client + server builds into build/
npm start              # react-router-serve build/server/index.js
npx react-router routes            # print the route tree
npx react-router typegen           # regenerate ./+types/* modules

Project Layout

my-app/
  app/
    root.tsx           # document shell, Layout, root ErrorBoundary
    routes.ts          # the route config, all routes declared here
    routes/
      home.tsx         # a route module
      about.tsx
    app.css
  public/
  react-router.config.ts   # ssr, prerender, basename, future
  vite.config.ts           # reactRouter() plugin
  .react-router/types/     # generated, gitignored
// vite.config.ts
import { reactRouter } from "@react-router/dev/vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [reactRouter()],
});

A Route Module

One file per route. Exports are the API: the default export renders, and loader / action run on the server. The generated Route namespace types the props and the handler args from the route path.

// app/routes/product.tsx
import type { Route } from "./+types/product";
import { Form } from "react-router";

export async function loader({ params }: Route.LoaderArgs) {
  return { product: await getProduct(params.id) };
}

export async function action({ request }: Route.ActionArgs) {
  const form = await request.formData();
  await addToCart(form.get("id"));
  return { added: true };
}

export default function Product({
  loaderData,
  actionData,
}: Route.ComponentProps) {
  return (
    <div>
      <h1>{loaderData.product.name}</h1>
      <Form method="post">
        <button name="id" value={loaderData.product.id}>Add</button>
      </Form>
      {actionData?.added ? <p>In cart</p> : null}
    </div>
  );
}
// app/routes.ts
import { type RouteConfig, index, route } from "@react-router/dev/routes";

export default [
  index("routes/home.tsx"),
  route("products/:id", "routes/product.tsx"),
] satisfies RouteConfig;

The Three Modes

ModeYou writeYou getPick it when
Frameworkroutes.ts plus route modules, Vite pluginSSR or SPA or prerender, loaders and actions, code splitting, typegenDefault. Any new app, and anything that wants server data
DatacreateBrowserRouter route objects plus RouterProviderLoaders, actions, fetchers, error boundaries, client side onlyYou already own the server and just want data APIs in the browser
Declarative<BrowserRouter> plus <Routes> and <Route>URL matching, Link, useNavigate, nothing elseA small client app, or you fetch with something else entirely

Data and Declarative mode are the labeled exception throughout this sheet. They are still supported and still shipped from the same package, they just are not the starting point anymore.

Reading the Docs

Every API page on reactrouter.com is tagged with the modes it works in. [MODES: framework] means the API only exists in Framework mode, and [MODES: framework, data] covers both. Anything tagged unstable_ can break in a minor release, so treat it as opt in.