React Router vs. React Router DOM: Which One Should You Use?
If you are building a React application and need to implement routing, you have likely run into two popular packages on npm: react-router and react-router-dom. This is a common source of confusion for beginners and intermediate developers alike. Why are there two packages, how do they differ, and which one should you install for modern web applications?
The Short Answer: Which One to Install?
If you are building a website or a web application, you should install react-router-dom. You do not need to install both packages manually.
npm install react-router-dom
When you install react-router-dom, npm automatically installs the core react-router package as a dependency, and re-exports all of its core components and hooks. This means you get everything you need with a single installation.
Understanding the Difference
To understand why these packages are separated, it helps to look at the architecture of React Router. The library is split into three main packages to support different environments:
react-router(The Core): This package contains the core routing logic, state management, hooks (likeuseLocationanduseParams), and components that are platform-agnostic. It does not contain any DOM-specific code.react-router-dom(For Web): This is the web-specific wrapper. It imports everything from the corereact-routerpackage and adds DOM-aware components like<BrowserRouter>,<Link>(which renders an HTML<a>tag), and<NavLink>.react-router-native(For Mobile): This is the React Native wrapper. It imports the corereact-routerlogic and provides components optimized for mobile development, such as<NativeRouter>.
Modern Best Practices for React Router (v6+)
If you are learning React Router today, you should focus on React Router v6 and above. The library underwent a massive evolution in version 6.4, introducing powerful data-loading APIs. Here are some pro tips to build fast, modern web applications:
1. Use the Data APIs (createBrowserRouter)
Instead of defining your routes purely inside JSX with <BrowserRouter>, the recommended modern approach is to use createBrowserRouter. This enables new features like data loaders, actions, and automatic error boundaries.
import { createBrowserRouter, RouterProvider } from "react-router-dom";
const router = createBrowserRouter([
{
path: "/",
element: <RootLayout />,
children: [
{
path: "dashboard",
element: <Dashboard />,
loader: async () => {
return fetch("/api/user-data");
}
}
]
}
]);
function App() {
return <RouterProvider router={router} />;
}
2. Leverage Nested Routing and <Outlet />
Nested routing allows you to keep persistent layouts (like sidebars and navbars) on the screen while only swapping out the inner content. Use the <Outlet /> component to render the child routes inside your parent layout.
import { Outlet } from "react-router-dom";
function RootLayout() {
return (
<div>
<Navbar />
<main>
<Outlet /> {/* Child routes will render here */}
</main>
</div>
);
}
3. Fetch Data Early with Loaders
In older versions of React, you had to fetch data inside a useEffect hook, which often led to loading spinners and layout shifts. With React Router v6's loader function, data fetching starts before the component even renders, making your application feel incredibly fast and responsive.
Summary
To summarize, react-router-dom is the only package you need to install for web development. It includes the core routing capabilities of react-router and adds the DOM-specific components needed to navigate web pages. Start your learning journey with React Router v6+ using createBrowserRouter to ensure your applications are modern, performant, and scale easily.