# Understanding the Different Router Modes in React Router: Declarative, Data, and Framework Explained

> Explore React Router modes: Declarative, Data, and Framework. Choose the right setup for your SPA or full-stack application needs.

- Repository: [Remix/react-router](https://github.com/remix-run/react-router)
- Tags: deep-dive
- Published: 2026-03-06

---

**React Router offers three primary router modes—Declarative, Data, and Framework—that are architecturally additive, allowing you to choose between minimal setup for simple SPAs and full-stack features for complex applications.**

The `remix-run/react-router` repository provides these distinct APIs to match your application's complexity and your team's infrastructure needs. Each mode builds upon the previous one, creating a clear upgrade path from basic client-side routing to fully type-safe, file-system based routing with automatic code-splitting.

## The Three Router Modes

React Router organizes its capabilities into three layers. The relationship is hierarchical: **Framework mode contains Data mode, which contains Declarative mode**. According to the official documentation in [`/docs/start/modes.md`](https://github.com/remix-run/react-router/blob/main//docs/start/modes.md), features are strictly additive, meaning you choose based on how much architectural control you want to retain versus how much infrastructure you want the library to handle.

### Declarative Mode: Component-Based Routing

**Declarative mode** uses the `<BrowserRouter>` or `<HashRouter>` components to create a plain router instance directly in your React tree. This is the traditional approach that maps URLs to components without built-in data loading.

In [`/packages/react-router/lib/dom/lib.tsx`](https://github.com/remix-run/react-router/blob/main//packages/react-router/lib/dom/lib.tsx) (lines 818-828), the `BrowserRouter` component is implemented as a thin wrapper that instantiates a history object and provides it via context. This mode supports essential navigation via `<Link>` and `useNavigate`, plus location state access through `useLocation`.

**When to use:** Choose Declarative mode for small applications, prototypes, or Create React App projects where you need basic URL-to-component matching without route-level data fetching or pending UI states. It is ideal when you already manage data loading separately from routing.

### Data Mode: Object-Based Routers with Loaders and Actions

**Data mode** introduces the `createBrowserRouter()` factory function and `<RouterProvider>` component. Unlike Declarative mode, the router object lives *outside* React rendering, enabling the router to drive data fetching before components render.

Implemented in [`/packages/react-router/lib/dom/lib.tsx`](https://github.com/remix-run/react-router/blob/main//packages/react-router/lib/dom/lib.tsx) (lines 645-665), `createBrowserRouter` creates a data router that supports route-level `loader` functions for fetching data, `action` functions for mutations, and `useFetcher` for pending UI without navigation. This architecture exposes hooks like `useLoaderData` and `useActionData` that connect your components to resolved route data.

**When to use:** Select Data mode when you need data fetching tied to routes but want to retain control over your bundler, server-side rendering implementation, or caching strategies. It is perfect for existing applications using React Router v6.4 data APIs that require custom adapters or specific build pipelines.

### Framework Mode: Zero-Config Full-Stack Routing

**Framework mode** wraps Data mode with a Vite plugin (`@react-router/dev/routes`) that provides file-system routing, type-safe route parameters, and intelligent code-splitting. Instead of manually defining route objects, you export a route configuration from [`routes.ts`](https://github.com/remix-run/react-router/blob/main/routes.ts).

The Vite plugin (located in [`/packages/react-router-dev/vite/plugin.ts`](https://github.com/remix-run/react-router/blob/main//packages/react-router-dev/vite/plugin.ts)) reads your route manifest, generates type-safe `Route` types, and automatically code-splits route modules. This mode implements the **Route Module API**, where files export `loader`, `action`, `ErrorBoundary`, and component functions that the framework wires together automatically.

**When to use:** Framework mode is optimal for full-stack applications requiring SSR/SSG, teams seeking a Remix-like developer experience without boilerplate, or projects where type-safe links and automatic bundle optimization are priorities.

## Implementation Examples

### Declarative Mode Setup

Mount the router as a component wrapper:

```tsx
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
);

```

### Data Mode Configuration

Define routes as objects with data capabilities:

```tsx
// src/router.ts
import {
  createBrowserRouter,
  RouterProvider,
} from "react-router";

const router = createBrowserRouter([
  {
    path: "/",
    Component: () => <h1>Home</h1>,
    loader: async () => {
      const data = await fetch("/api/home");
      return data.json();
    },
  },
]);

// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider } from "react-router";
import router from "./router";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <RouterProvider router={router} />,
);

```

### Framework Mode with Route Modules

Configure routes in [`routes.ts`](https://github.com/remix-run/react-router/blob/main/routes.ts) and implement route modules:

```tsx
// routes.ts
import { index, route } from "@react-router/dev/routes";

export default [
  index("./home.tsx"),
  route("products/:pid", "./product.tsx"),
];

```

```tsx
// app/product.tsx
import { Route } from "./+types/product.tsx";

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

export default function Product({ loaderData }: Route.ComponentProps) {
  return <div>{loaderData.product.name}</div>;
}

```

The Framework mode implementation details are documented in [`/docs/start/framework/route-module.md`](https://github.com/remix-run/react-router/blob/main//docs/start/framework/route-module.md), which defines the Route Module API surface.

## Decision Guide: Selecting the Right Mode

**Choose Framework mode** when you want the "zero-config" experience of file-system routing, automatic type generation for route parameters, and seamless SPA/SSR/SSG strategies. The documentation in [`/docs/start/modes.md`](https://github.com/remix-run/react-router/blob/main//docs/start/modes.md) (lines 95-102) identifies this as the best choice for teams new to React Router or projects requiring server-side rendering without custom infrastructure.

**Choose Data mode** when you have an existing build pipeline and want data router capabilities—loaders, actions, and pending states—while maintaining full control over server adapters and bundler configuration. As noted in [`/docs/start/modes.md`](https://github.com/remix-run/react-router/blob/main//docs/start/modes.md) (lines 106-110), this suits existing v6.4 data router applications that are currently working well.

**Choose Declarative mode** when you need minimal routing for simple SPAs or when your application already implements a separate data layer that handles its own loading states. The documentation specifies this for basic route matching needs in [`/docs/start/modes.md`](https://github.com/remix-run/react-router/blob/main//docs/start/modes.md) (lines 113-118).

## Summary

- **Declarative mode** (`<BrowserRouter>`) provides basic URL-to-component matching via React context in [`/packages/react-router/lib/dom/lib.tsx`](https://github.com/remix-run/react-router/blob/main//packages/react-router/lib/dom/lib.tsx), suitable for simple SPAs without data loading.
- **Data mode** (`createBrowserRouter`) adds object-based route configuration with `loader` and `action` functions, enabling pre-render data fetching and mutation handling through `RouterProvider`.
- **Framework mode** leverages the Vite plugin in [`/packages/react-router-dev/vite/plugin.ts`](https://github.com/remix-run/react-router/blob/main//packages/react-router-dev/vite/plugin.ts) to provide type-safe, file-system based routing with automatic code-splitting and the Route Module API.
- The modes are additive: Framework includes all Data features, which include all Declarative features.

## Frequently Asked Questions

### Can I migrate from Declarative mode to Data mode incrementally?

Yes, migration is incremental because the modes are architecturally additive. You can replace `<BrowserRouter>` with `createBrowserRouter` and `<RouterProvider>` in your entry point, then gradually add `loader` and `action` functions to specific routes while keeping existing components unchanged.

### Does Framework mode require using Vite?

Yes, Framework mode is currently implemented through the `@react-router/dev` Vite plugin located in [`/packages/react-router-dev/vite/plugin.ts`](https://github.com/remix-run/react-router/blob/main//packages/react-router-dev/vite/plugin.ts). The plugin handles route manifest generation, type generation, and code-splitting. If you use a different bundler, you should use Data mode instead.

### What happens to my existing React Router v5 code in these modes?

Declarative mode maintains compatibility with v5-style component-based routing. However, v5's `<Switch>` and `useHistory` APIs are replaced by `<Routes>` and `useNavigate`. Data and Framework modes require v6.4+ APIs and do not support legacy v5 patterns like static `<Route>` children outside of `<Routes>`.

### Is Data mode required to use the `loader` and `action` functions?

Yes, `loader` and `action` functions are only available in Data mode and Framework mode (which builds on Data mode). These functions depend on the router object created by `createBrowserRouter` to handle data fetching outside the React render cycle, as implemented in [`/packages/react-router/lib/dom/lib.tsx`](https://github.com/remix-run/react-router/blob/main//packages/react-router/lib/dom/lib.tsx).