React Router Declarative, Data, and Framework Modes Compared

Compare React Router's Declarative, Data, and Framework modes. Learn how each sets up routes, loads data, and when to choose each one.

6 min read

React Router has three modes: Declarative, Data, and Framework. They are additive layers, so each mode adds features while asking you to give up a little architectural control. The right mode depends on how much you want the router to do for you.

The three modes at a glance

ModeRoute setupData featuresServer rendering
DeclarativeComponents in JSXNoNo
DataRoute objectsLoaders and actionsNo
FrameworkFile routes with a Vite pluginLoaders and actionsSPA, SSR, static

Declarative mode only matches URLs to components. Data mode adds loaders and actions that run in the browser. Framework mode wraps data mode with a Vite plugin and can move loaders and actions to the server.

Each step up adds capabilities at the cost of some control, so the decision is about that tradeoff.

Declarative mode: components in JSX

Declarative mode is the smallest layer. You render the router components directly in JSX, with no route objects and no data functions.

App.jsxApp.jsx
import { BrowserRouter, Routes, Route } from "react-router";
import Home from "./pages/Home.jsx";
import About from "./pages/About.jsx";
export default function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
}

This covers URL matching, navigation, and active link styling, and nothing else. There is no loader, no pending state, and no server rendering. It is the setup from the React Router tutorial, and it fits a marketing site or a simple client-side app whose data layer already lives outside React.

Because there are no loaders, the initial HTML has no data, and each page fetches on the client.

Data mode: route objects with loaders

Data mode moves the route configuration out of JSX and into objects passed to createBrowserRouter. Each route can carry a loader and an action.

App.jsxApp.jsx
createBrowserRouter([
  {
    path: "/",
    Component: Home,
    loader: async () => ({ posts: await fetchPosts() }),
  },
]);

The loader runs before the component renders, and useLoaderData reads its result. Actions handle form submissions with automatic revalidation. You still own the bundler and the server, so the router never renders on the server in this mode.

It is the middle ground, with the data features of framework mode but none of its file conventions or server rendering. The full data flow is in React Router loaders and actions explained.

Framework mode: file routes and type safety

Framework mode is data mode plus a Vite plugin. Routes live in a routes.ts file, and each route module exports its loader, action, and component with generated types.

index.tsindex.ts
import { route } from "@react-router/dev/routes";
 
export default [
  route("products/:pid", "./product.tsx"),
];

The route helper maps a URL pattern to a file. Layouts and index routes use the layout and index helpers, and a catch-all uses the star pattern.

App.tsxApp.tsx
import type { Route } from "./+types/product.tsx";
 
export async function loader({ params }: Route.LoaderArgs) {
  return { product: await getProduct(params.pid) };
}
 
export default function Product({ loaderData }: Route.ComponentProps) {
  return <div>{loaderData.product.name}</div>;
}

Route.LoaderArgs and Route.ComponentProps are generated from the route config, so params and loader data stay typed. Framework mode also renders on the server and splits code automatically, unlike the manual split in how to lazy load routes in React. Scaffold a new project with npx create-react-router@latest.

A special root.tsx module wraps every route, holding the document shell and global providers.

Which mode should you use?

  • Framework mode: choose it when you are new, migrating from Next.js, or want server rendering, code splitting, and type-safe routes without wiring them yourself.
  • Data mode: choose it when you want loaders and actions but prefer to control the bundler and the server yourself.
  • Declarative mode: choose it when you only need URL matching, links, and navigation with no data layer.

The modes are not tiers of quality, just different amounts of built-in behavior.

One common confusion

None of the modes is deprecated, and every mode can target any deployment. Declarative mode is not a legacy fallback, it is the correct choice when there is no data to load. The layers are additive, so an app can start declarative and adopt data or framework features later without rewriting its pages.

Rune AI

Rune AI

Key Insights

  • Declarative mode renders routes in JSX with no data features.
  • Data mode adds loaders and actions through route objects.
  • Framework mode adds file routes, type safety, and server rendering.
  • Pick the mode by how much control you want to keep.
RunePowered by Rune AI

Frequently Asked Questions

Which mode should a beginner choose?

Framework mode. It provides the full default setup with type safety, server rendering, and code splitting, so there is less to wire up by hand.

Is declarative mode deprecated?

No. Declarative mode is the right choice when you only need URL matching and navigation and have no data layer to load.

Can I switch modes later?

Yes. The modes are additive and share one package. A declarative app can adopt data mode features, and data mode can move to the framework mode Vite plugin.

Conclusion

React Router's three modes are additive layers. Declarative mode matches URLs to components, Data mode adds loaders and actions, and Framework mode wraps it all in a Vite plugin with type safety and server rendering. Pick the mode that matches how much the router should do for you.