Choosing the right React Router v7 mode for your project
Choosing the right routing strategy is one of the first big decisions when building a React app. With the release of React Router v7, routing has evolved beyond simple navigation into a set of modes that can also manage data, handle mutations, and even power full-stack applications.
In this guide, we’ll break down the three modes React Router v7 offers: declarative, data, and framework and, explore when to use each. By the end, you’ll not only understand how these modes differ, but you’ll also know exactly which one fits your project’s needs.
Why are there different modes?
React Router started as a routing library for Single-Page Applications (SPAs). In v4, the authors added support for routing React Native apps, which meant there were now two ways to use the library. To distinguish between these use cases, the team released two different libraries: react-router-dom
for Web Apps and react-router-native
for React Native.
React Router kept evolving, but maintained that distinction between DOM and React Native. However, at the same time, the React Router team was developing a full-stack React framework called Remix. Remix used React Router to manage its routing. The team also kept pushing the capabilities of the Router.
Eventually, in the v6 release, React Router became more than just a routing library. It also started to handle data loading and mutations in routes. Data handling patterns from Remix were ported to React Router as the authors thought those patterns would be beneficial to the routing library.
In v7, the React Router team decided to combine Remix and React Router, releasing them as just one library: react-router
. They did this mainly because the two libraries had grown very similar over time, and they wanted to free up the Remix brand for something more ambitious. React Router was transformed from a simple routing library to a full-stack framework.
Due to the multiple use cases of React Router v7, the team grouped its functionalities into different modes. This was to make it more intuitive for developers to adopt. This differentiation was also important to anyone migrating from Remix to React Router. It was clearer what the migration path looked like and what features were made for the full-stack framework.
Note: The v7 release also dropped support for React Native, so the library is now only imported as react-router
.
Modes | Declarative Mode | Data Mode | Framework Mode |
---|---|---|---|
Previous version | React Router v5/v6 | React Router v6.4+ | Remix v2 |
Server-side rendering | Not supported | Supported (with DIY setup) | Supported |
Typesafety | Not supported | Not supported | Supported |
Recommended use case | Simple routing | Routing and data handling | Full-stack development |
Understanding React Router modes
In the sections below, we’ll walk through each of the three React Router v7 modes: declarative, data, and framework. For each, we’ll cover what it does, its pros and cons, and the scenarios where it’s the best fit.
Declarative mode
The declarative mode of React Router allows simple declarative routing for SPAs. With this mode, one can set up routes with JSX, use React Router’s built-in components like <Link>
and <NavLink>
, nest routes with <Outlet />
, and has access to hooks like useNavigate
and useLocation
.
This example illustrates how to create a simple index route in declarative mode:
import React from "react"; import ReactDOM from "react-dom/client"; import { BrowserRouter, Routes, Route } from "react-router"; import App from "./app"; const root = document.getElementById("root"); ReactDOM.createRoot(root).render( } /> , );
Pros of using the declarative mode in React Router are:
- Efficient SPA routing – This mode works well for the basic routing needs of React apps. As mentioned earlier, it offers built-in components and functions that abstract away frequently needed utilities. It then presents them with declarative and easy-to-use APIs
- Simple learning curve – Out of all the modes in React Router, this is the most easy to get started with. It has mostly simple APIs that solve routing problems in a straightforward and intuitive manner
- Small bundle footprint – Due to tree-shaking by bundlers, using React Router’s declarative mode leaves a small footprint on the resulting build bundle. You end up getting excellent routing functionalities without having a bloated application
Cons of using the declarative mode in React Router are:
- Custom data loading – Because the authors of React Router intended this mode to be for basic routing, developers have to look to other solutions to handle data loading for their routes. Other React Router modes, however, handle this optimally with route loaders
- Limited functionality – Other modes of React Router provide a lot more built-in components and functions for users. One example is the
<Form/>
component and its associated hooks and functions
Choose React Router’s declarative mode when:
- You want to get familiar with the React Router ecosystem
- You need simple routing for your SPA that just works
Data mode
Think of data mode in React Router as an extended declarative mode. While declarative mode is minimal, data mode gives access to more tools. This mode configures routes outside of React’s rendering, which allows React Router to perform services like data loading for routes, handling data mutations with actions, robust form management, and many more.
The example below shows how to create a simple route in data mode:
import { createBrowserRouter } from "react-router"; function Root() { return <h1>Hello world</h1>; } const router = createBrowserRouter([ { path: "/", Component: Root }, ]);
The Pros of using data mode are:
- Extra components and APIs – This mode provides the user with more built-in components, in addition to most of the functionality in declarative mode. This makes it an even more robust routing solution
- Allows further customization – Developers can use the React Router data mode as a foundation to build their own framework. If, for some reason, they like data mode and want to create a custom framework around it, they are welcome to do so
- Support for Server-Side Rendering (SSR) – With declarative mode, the docs are not clear on how to use it to build SSR apps. However, there is documentation on how to combine this mode with SSR in case that is what a user wants
The cons of using data mode are:
- Slight learning curve – This mode takes a lot more time to get used to than declarative mode. It has a bit of a learning curve before one can get the benefits from it
- Users may not need all the features – The user may not make full use of the data mode. In that case, they are probably better off fixing some of those problems themselves and working with declarative mode instead of trying to learn the data mode
Choose data mode when:
- You need a robust way to handle data between routes
- You want to build a custom framework with a React Router base
Framework mode
The framework mode of React Router is essentially a data mode as a packaged and polished full-stack React framework. Along with the benefits of data mode, framework mode adds enhancements like typesafety, straightforward config for SPAs, SSRs, or Static generation.
A major addition in this mode is file-based routing, which allows you to define routes directly from the file system rather than manually configuring them. This makes organizing routes more intuitive and helps scale larger applications.
Framework mode is also positioned as an alternative to other full-stack React frameworks like Next.js and TanStack Start.
Below is an example that shows how to define routes in framework mode:
// src/routes.ts import { type RouteConfig, route, index, layout, prefix, } from "@react-router/dev/routes"; export default [ index("./home.tsx"), route("about", "./about.tsx"), layout("./auth/layout.tsx", [ route("login", "./auth/login.tsx"), route("register", "./auth/register.tsx"), ]), ...prefix("concerts", [ index("./concerts/home.tsx"), route(":city", "./concerts/city.tsx"), route("trending", "./concerts/trending.tsx"), ]), ] satisfies RouteConfig;
The pros of framework mode are:
- All-in-one package – The framework mode is the most robust and versatile in React Router. Apart from its well-mapped rendering strategies, one can also perform more operations like prefetching links, among others
- Better organization – Using the framework mode generally creates a much more organized codebase than using the data mode. A data mode codebase can sometimes feel improvised, while framework mode has a cleaner structure
- Type safety – In all the modes of React Router, framework mode is the only one that can guarantee type safety. Framework mode generates important types for every route. This is a huge advantage of using framework mode over the others
On the other hand, the cons of framework mode are:
- Relatively steep learning curve – Out of all the modes, framework mode has a slightly steeper learning curve. Note that this curve would be reduced if the user has had prior experience with data mode
- Not always the right tool – Framework mode is not always the right mode for the job. For example, if a user prioritizes control, then data mode might be the better tool for that job. If they prioritize simplicity, then declarative mode might be the better tool
Choose framework mode when:
- You want to build React apps with a well-structured framework
- You want to use React Router with typesafety
- need an alternative to Next.js, or TanStack Start
Conclusion
React Router has grown from a simple client-side routing tool into a flexible framework with multiple modes. While the options in v7 can feel overwhelming at first, the key is matching the mode to your project’s needs: declarative for simple SPAs, data for apps that need routing plus data handling, and framework for full-stack development with type safety and SSR support.
With these distinctions in mind, you can approach new projects confidently, knowing which mode to reach for and why.
The post Choosing the right React Router v7 mode for your project appeared first on LogRocket Blog.
This post first appeared on Read More