react-router serves as the core routing logic for React applications, while react-router-dom and react-router-native provide environment-specific bindings for web and mobile platforms respectively. @reach/router was a popular alternative that merged into the react-router project with version 6, making it a legacy package. Together, these tools manage navigation, URL synchronization, and component rendering based on location, but they target different stages of the ecosystem lifecycle and deployment environments.
Navigating between views is a fundamental requirement for single-page applications. The React ecosystem offers a family of routing packages that share a common history but serve distinct purposes. react-router provides the core logic, react-router-dom adapts it for the web, react-router-native adapts it for mobile, and @reach/router represents the legacy predecessor. Let's compare how they handle real-world routing tasks.
@reach/router is no longer maintained.
react-router starting at version 6.// @reach/router: Legacy (Deprecated)
// Do not use in new projects
import { Router, Route } from "@reach/router";
<Router>
<Route path="/about" component={About} />
</Router>
react-router is the active core library.
// react-router: Core Logic
// Usually installed as a dependency, not directly
import { Routes, Route } from "react-router";
<Routes>
<Route path="/about" element={<About />} />
</Routes>
react-router-dom is the active web standard.
// react-router-dom: Web Standard
// Recommended for web apps
import { Routes, Route } from "react-router-dom";
<Routes>
<Route path="/about" element={<About />} />
</Routes>
react-router-native is the active mobile standard.
// react-router-native: Mobile Standard
// Recommended for mobile apps
import { Routes, Route } from "react-router-native";
<Routes>
<Route path="/about" element={<About />} />
</Routes>
@reach/router was designed primarily for the web.
// @reach/router: Web Focused
import { Router } from "@reach/router";
// Uses browser history internally
<Router basepath="/app">
<Home path="/" />
</Router>
react-router is platform independent.
// react-router: Platform Independent
import { Router, Routes } from "react-router";
// Requires custom history prop
<Router history={customHistory}>
<Routes>...</Routes>
</Router>
react-router-dom is built for browsers.
BrowserRouter which wraps the HTML5 history API.Link components that render <a> tags.// react-router-dom: Browser Specific
import { BrowserRouter, Link } from "react-router-dom";
<BrowserRouter>
<Link to="/about">About</Link>
</BrowserRouter>
react-router-native is built for mobile.
NativeRouter which uses in-memory history.Link components that render TouchableOpacity.// react-router-native: Mobile Specific
import { NativeRouter, Link } from "react-router-native";
<NativeRouter>
<Link to="/about">About</Link>
</NativeRouter>
@reach/router used a simpler hook set in version 3.
useLocation and navigate were available but less consistent.// @reach/router: Legacy Navigation
import { navigate } from "@reach/router";
function Button() {
return <button onClick={() => navigate("/home")}>Go</button>;
}
react-router provides the core navigation hooks.
useNavigate is the standard way to change routes programmatically.// react-router: Core Navigation
import { useNavigate } from "react-router";
function Button() {
const navigate = useNavigate();
return <button onClick={() => navigate("/home")}>Go</button>;
}
react-router-dom adds web-specific link behavior.
Link prevents full page reloads automatically.NavLink supports active state styling for menus.// react-router-dom: Web Links
import { Link, NavLink } from "react-router-dom";
function Menu() {
return <NavLink to="/home" className={({ isActive }) => isActive ? "bold" : ""}>Home</NavLink>;
}
react-router-native adds mobile-specific touch handling.
Link uses native touchables for better performance.underlayColor props allow visual feedback on press.// react-router-native: Mobile Links
import { Link } from "react-router-native";
function Menu() {
return <Link to="/home" underlayColor="#eee"><Text>Home</Text></Link>;
}
@reach/router did not have built-in data loading.
useEffect or external libraries like React Query.// @reach/router: Manual Data Loading
function Profile() {
const [data, setData] = useState(null);
useEffect(() => { fetch("/api").then(setData) }, []);
return <div>{data?.name}</div>;
}
react-router v6.4+ introduced data routers.
loader functions run before the component renders.// react-router: Core Data Loading
// Conceptual example using createRouter
const router = createRouter({
routes: [{ path: "/profile", loader: loadProfile }]
});
react-router-dom fully supports data loading APIs.
createBrowserRouter enables loader and action usage.useLoaderData hook accesses the fetched data safely.// react-router-dom: Web Data Loading
import { createBrowserRouter, useLoaderData } from "react-router-dom";
const router = createBrowserRouter([{
path: "/profile",
loader: async () => fetch("/api"),
element: <Profile />
}]);
react-router-native has limited data router support currently.
useEffect or React Query.// react-router-native: Mobile Data Loading
// Common pattern using hooks
function Profile() {
const [data, setData] = useState(null);
useEffect(() => { fetch("/api").then(setData) }, []);
return <View>{data && <Text>{data.name}</Text>}</View>;
}
| Feature | @reach/router | react-router | react-router-dom | react-router-native |
|---|---|---|---|---|
| Status | ⚠️ Deprecated | ✅ Active Core | ✅ Active Web | ✅ Active Mobile |
| Target | 🌐 Web (Legacy) | ⚙️ Logic Only | 🌐 Browser | 📱 React Native |
| Router | <Router> | <Router> (Custom) | <BrowserRouter> | <NativeRouter> |
| Links | <Link> | N/A | <Link> () | <Link> (Touchable) |
| Data API | ❌ None | ⚙️ Core Support | ✅ Full Support | ⚠️ Limited Support |
@reach/router is a legacy tool that should be retired.
react-router-dom is the only sustainable path.react-router is the engine under the hood.
react-router-dom is the default for web developers.
react-router-native is the choice for mobile teams.
Final Thought: Stick to the official react-router family for new work.
react-router-dom for web and react-router-native for mobile.@reach/router to prevent future migration headaches.Choose react-router only if you are building a custom routing environment or a library that needs to work across multiple platforms without binding to DOM or Native specifics. For standard application development, this package is usually a dependency of react-router-dom or react-router-native rather than a direct install target.
Choose react-router-dom for any standard web application running in a browser. It includes all core routing features plus essential web components like BrowserRouter, Link, and NavLink. This is the default choice for 99% of React web projects and provides the best integration with browser history APIs.
Do not choose this package for new projects. It is officially deprecated and merged into react-router version 6. Using it introduces technical debt and limits access to modern features like data loading and improved hooks. Migrate existing projects to react-router-dom to ensure long-term maintenance and security.
Choose react-router-native when building mobile applications using React Native. It replaces web-specific components with mobile-friendly equivalents like NativeRouter and touch-optimized Link components. It ensures navigation feels natural on iOS and Android while sharing the same core logic as the web version.
react-router is the primary package in the React Router project.
npm i react-router