React Router v7: The Evolution React Needed

posted Originally published at dev.to 3 min read

If you're reading this, you're probably working with React or learning how to use it. And if that’s the case, you’ve surely heard of react-router, the most popular library for routing in React apps for years.

But what you may not know is that in its latest version, React Router has evolved significantly. It now incorporates concepts from Remix like loaders, actions, ErrorBoundaries, SSR support, and more.

Remix? That’s right. The Remix framework has always been built on top of React Router. But with this new version (v7), the experience has been unified—now you can use that same architecture directly in React Router, without needing to adopt a full framework.

What Does React Router v7 Offer?

The best way to understand what React Router v7 brings is by looking at its three usage modes, each designed for different levels of complexity and application needs:

  1. Declarative Mode
  2. Data Mode
  3. Framework Mode

Let’s break down what each one is and when to use them.

Declarative Mode

This is the classic approach you’re probably already familiar with. You use components like <Routes> and <Route> to define your routes, along with hooks like useNavigate, useParams, and so on.

<Routes>
  <Route index element={<Home />} />
  <Route path="about" element={<About />} />

  <Route element={<AuthLayout />}>
    <Route path="login" element={<Login />} />
    <Route path="register" element={<Register />} />
  </Route>

  <Route path="concerts">
    <Route index element={<ConcertsHome />} />
    <Route path=":city" element={<City />} />
    <Route path="trending" element={<Trending />} />
  </Route>
</Routes>

This mode is perfect if you want a simple SPA using your own bundler (Vite, Webpack...), managing state with Zustand, Redux, or react-query, and you don’t need server-side rendering (SSR).

Data Mode

This is where React Router v7 really transforms. Instead of using components to define routes, you use a route config object. Each route can have a loader (to fetch data) and an action (to handle forms or mutations).

const router = createBrowserRouter([
  {
    path: "/",
    element: <div>Hello World</div>,
  },
]);

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

A more complete example with a loader and action:

createBrowserRouter([
  {
    path: "/items",
    loader,
    action,
    Component: Items,
  },
]);

async function loader() {
  const items = await fakeDb.getItems();
  return { items };
}

async function action({ request }) {
  const data = await request.formData();
  await fakeDb.addItem({ title: data.get("title") });
  return { ok: true };
}

function Items() {
  const data = useLoaderData();
  return (
    <div>
      <TodoList items={data.items} />
      <Form method="post">
        <input type="text" name="title" />
        <button type="submit">Crear</button>
      </Form>
    </div>
  );
}

This mode is ideal if you're building a complex SPA and want to avoid useEffect chaos, centralizing your data flow. You can also keep your current stack and deploy wherever you want (Vercel, Netlify, Firebase, etc.).

I recommend checking out this ejemplos, and stay tuned—I'll be publishing more articles on how to make the most of this mode.

Framework Mode

This mode turns React Router into a full framework with SSR support. You start from scratch using a CLI, and it’s designed for apps that need SEO or super-fast initial loads.

It has the best TypeScript support, shares the loaders and actions concept from Data Mode, and gives you full control.

However, keep in mind:

  • You need to define your deployment setup from the start.
  • Not all libraries work well with SSR.
  • Your team should understand the difference between CSR and SSR.
  • It works best with Tailwind or styling approaches compatible with SSR.

That said, if your app is private or doesn’t need SEO, I’d recommend sticking with Declarative or Data Mode to avoid unnecessary complexity.

So, Is It Worth It?

Many React frameworks are adding complexity to the frontend with their latest updates. React Router v7 gives you a clear, flexible alternative:

  • Start with Declarative Mode if you just need routing.
  • Move to Data Mode to better manage data and forms.
  • And go full Framework Mode only if SSR is truly required.

All without locking yourself into a single approach from day one.

In upcoming posts, I’ll dive deeper into loaders, actions, and data-mode architecture—building projects from scratch, testing, and real-world integrations.

Are you interested in React Router v7? Want to see practical examples or comparisons with other solutions? Let me know in the comments—I’d love to hear from you.

If you read this far, tweet to the author to show them you care. Tweet a Thanks

Really appreciate the clear breakdown of React Router v7’s modes—makes the evolution much easier to grasp! I’m curious, for teams already using React Router v6, how smooth do you think the migration to Data Mode or Framework Mode will be? Any common challenges to watch out for?

Hi, that's an interesting question.
The migration to Data or Framework Mode from v6 starts by updating the version, which—even though it's a major release—does not introduce breaking changes.

Then, teams should decide whether they'll stick with a traditional SPA or move to SSR.
If they go with SPA, using Data Mode is very straightforward.
However, if they want to switch to SSR and Framework Mode, they'll need to adjust the bundler configuration to use the React Router plugin.

In my opinion, moving to Data Mode is the best approach. You can progressively shift your request logic from custom hooks or React Query into loader and action functions provided by React Router—you don’t have to do it all at once. This incremental adoption makes the transition much more manageable.

I would only apply Framework Mode with SSR—for example, in e-commerce sites, blogs, or landing pages.

More Posts

React Router Data Mode: Part 3 - Loaders and data fetching

Kevin Martinez - Jul 7

React Router Data Mode: Part 2 - Nested routes and outlets

Kevin Martinez - Jul 4

React Router Data Mode: Part 1 - Installation and first routes

Kevin Martinez - Jun 27

Learn how to Implement Public, Private, and Protected Routes in your React Application

Dr Prime - Oct 3, 2024

Frontend Development: React vs Angular - Getting Started

Deekshith Raj Basa - Mar 25
chevron_left