How To Compare React Router and Reach Router

Updated on August 3, 2021

William Le

How To Compare React Router and Reach Router

This tutorial is out of date and no longer maintained.


Reach Router is authored by Ryan Florence. If you recognize his name it’s because he’s the original co-author of React Router, which is currently the most popular routing library.

Both libraries appear to have identical purposes to provide a routing layer for the web. However, Reach Router is taking a fresh approach to the solution, and it also comes with accessibility (a11y) baked-in and working out of the box.

Warning: Since the original publication, it has been announced that React Router will adopt many of the features of Reach Router. You should consult the “Which Project Should I Choose Today?” section for your project’s needs.

In this article, you will compare React Router to Reach Router in order to better understand what each library supports and provides.


To follow along with this tutorial, you will need:

Comparing Set Up

Reach Router is very similar to React Router and uses similar namespaces like <Router>, <Link>, etc., but there are some noteworthy differences. Let’s consider a basic setup for both react-router and reach-router.

First, a setup using React Router:

React Router
import React from "react"; import { BrowserRouter as Router, Route } from "react-router-dom"; const App = () => { return ( <Router> <div> <h1>Global Party Supplies, Inc</h1> // PATHS <Route component={Home} path="/" exact/> // "/" <Route component={About} path="/about"/> // "/about" <Route component={Support} path="/support"/> // "/support" <Route component={Dashboard} path="/dashboard"/> // "/dashboard" <Route component={Invoices} path="/dashboard/invoices"/> // "/dashboard/invoices" <Route component={Team} path="/dashboard/team"/> // "/dashboard/team" <Route component={Report} path="/dashboard/:reportId"/> // "/dashboard/:reportId" </div> </Router> ); }

React Router has its own <Route> component that takes two props: component and path.

Here’s the same setup using Reach Router:

Reach Router
import React from "react"; import { Router } from "@reach/router"; const App = () => { return ( <div> <h1>Global Party Supplies, Inc</h1> <Router> // PATHS <Home path="/"/> // "/" <About path="about"/> // "/about" <Support path="support"/> // "/support" <Dashboard path="dashboard"> // "/dashboard" <Report path=":reportId"/> // "/dashboard/:reportId" <Invoices path="invoices"/> // "/dashboard/invoices" <Team path="team"/> // "/dashboard/team" </Dashboard> </Router> </div> ); }

The first impression is that this looks really clean. Reach Router doesn’t have a <Route> component. You just use the component itself (e.g., <Dashboard>)! Using nested JSX for subpaths (/dashboard/team) distinguishes itself from React Router.

But wait… there’s something weird here. At first glance you may think the <Report> route would intercept /dashboard/invoices and /dashboard/team, but it actually doesn’t!

Reach Router uses a point system to rank your route definitions by looking at the path value. When two paths seem to collide, params (:reportId) and wildcard (*) get low-priority, while explicit paths (invoices and teams) get higher priority. This means navigating to /dashboard/invoices actually works, and /dashboard/example goes to <Report>.

Comparing Params and Props

Now that we’ve explored the basic setup, let’s explore how you would pass data to routes.

First, reportId and salesData with React Router:

React Router
<Route path="/dashboard/:reportId" render={(props) => { return <Report {...props} salesData={true} /> }} /> const Report = ({ props, match }) => { return ( <h1> {match.params.reportId} // "match" is from react-router and {props.salesData} </h1> ) }

There’s more stuff involved with React Router, but this is normal fare if you’ve been using it for any amount of time.

Here’s the same example with Reach Router:

Reach Router
<Report path="dashboard/:reportId" // static routes work too :) salesData={this.state.salesData} /> const Report = (props) => { return ( <h1> {props.reportId} and {props.salesData} </h1> ) }

Note how reportId does not require match to access the URL parameters.

Next, let’s investigate how <Link>ing works in both libraries.

Comparing Linking

Both Reach Router and React Router export a <Link> component, but there are some differences. Let’s consider a <Dashboard> component which has several subpages.

First, with React Router:

React Router
import { Link } from "react-router-dom"; const Dashboard = ({ match, history }) => { return ( <div> <div> <Link to={`${match.url}/invoices`}>Invoices</Link> <Link to={`${match.url}/team`}>Team</Link> </div> <!-- content --> <div> <Link to="/">Home</Link> <Link to="/about">About</Link> <Link to="/support">Support</Link> <a onClick={history.goBack}>Go Back</a> </div> </div> ); }

With React Router you have to be specific with <Link> which usually means you’ll have to use match.url when you have subpaths beyond a root subpath (e.g., /host/path1/path2). Also, note that you have to programmatically goBack since there isn’t a utility for relative navigation.

Here’s the same example with Reach Router:

Reach Router
import { Link } from "@reach/router"; const Dashboard = () => { return ( <div> <div> <Link to="invoices">Invoices</Link> <Link to="team">Team</Link> </div> <!-- content --> <div> <Link to="/">Home</Link> <Link to="/about">About</Link> <Link to="/support">Support</Link> <Link to="../">Go Back</Link> </div> </div> ) }

Reach Router supports relative links! It also fully supports Unix directory navigation like <a> tags would.


In this article, you compared React Router to Reach Router in order to better understand what each library supports and provides.

Based on these comparisons, Reach Router is a very tempting alternative to React Router. Overall, it’s more elegant in conveying information when reading and writing the code. This shouldn’t come as a surprise as Ryan Florence is the co-author of react-router, and most hard-fought insights can only be gotten through time and experience.

Give Reach Router a try! The first v1.0 release was in May 2018 and GatsbyJS v2 has already opted for Reach Router against React Router.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
William Le


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
Leave a comment

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel