# Why Are My React Router Nested Routes Not Working? Common Pitfalls and Fixes

> Struggling with React Router nested routes not working? Discover common pitfalls like missing exact props or children and find quick fixes to get your routes functioning correctly.

- Repository: [Meta/react](https://github.com/facebook/react)
- Tags: how-to-guide
- Published: 2026-02-16

---

**React Router nested routes fail when the parent route lacks the `exact` prop (v5), omits `{props.children}` or `<Outlet>`, or when multiple router providers create conflicting contexts.**

React Router nested routes are a powerful pattern for building modular UIs, but they require precise configuration to function correctly. According to the `facebook/react` repository's nesting fixtures, most failures stem from misunderstanding how the router builds its matching tree and renders child components. This guide explains why your nested routes may not be rendering and how to fix them using patterns validated by the React core team.

## How React Router Builds the Route Tree

React Router constructs its routing tree by matching the current URL against the `path` props of `<Route>` components rendered within a **router context** (`<BrowserRouter>`, `<HashRouter>`, etc.). When a parent route matches, the router must still evaluate child routes to determine the final UI composition.

If a nested `<Route>` never receives the router context—or if the parent route's component never renders its children—the router cannot match deeper paths. This is why the `fixtures/nesting` demo in the React repository emphasizes maintaining a single, consistent router provider across the entire application tree.

## Common Reasons React Router Nested Routes Fail

### Missing `exact` Prop on Parent Routes (v5)

In React Router v5, the `<Switch>` component renders the **first** child `<Route>` that matches the current location. If the parent route uses `path="/"` without the `exact` prop, it matches every URL, preventing subsequent routes from ever being evaluated.

```jsx
// ❌ Broken: Parent consumes all routes
<Switch>
  <Route path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route path="/dashboard" component={Dashboard} />
</Switch>

// ✅ Fixed: Add exact to parent or reorder
<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route path="/dashboard" component={Dashboard} />
</Switch>

```

### Parent Component Not Rendering Children

Even when routes match correctly, the UI won't appear if the parent component doesn't render its children. In React Router v5, you must explicitly render `{props.children}` or use the `component`/`render` prop to include nested `<Switch>` elements. In v6, you must use `<Outlet>`.

```jsx
// ❌ Broken: Children never rendered (v5)
function Dashboard({ match }) {
  return <h2>Dashboard</h2>;
  // Missing {props.children} or nested Switch
}

// ✅ Fixed: Render children explicitly (v5)
function Dashboard({ match }) {
  return (
    <div>
      <h2>Dashboard</h2>
      <Switch>
        <Route path={`${match.path}/stats`} component={Stats} />
        <Route path={`${match.path}/settings`} component={Settings} />
      </Switch>
    </div>
  );
}

```

### Multiple Router Providers Breaking Context

Creating a new router instance inside a child component—such as wrapping a lazily-loaded subtree with its own `<BrowserRouter>`—breaks the shared context. Each router maintains its own history object, causing the parent and child routes to operate in isolated namespaces.

The [`fixtures/nesting/src/modern/lazyLegacyRoot.js`](https://github.com/facebook/react/blob/main/fixtures/nesting/src/modern/lazyLegacyRoot.js) file in the React repository demonstrates how to lazy load components while preserving the single router context established at the application root.

### Incorrect Route Ordering

When using `<Switch>` (v5) or `<Routes>` (v6), order matters. Generic paths like `path="/"` or `path="/dashboard"` should appear after more specific routes, or they will intercept matches intended for deeper paths like `/dashboard/stats`.

## Working Examples from the React Repository

The React repository's `fixtures/nesting` directory provides validated implementations for both React Router v5 and v6 patterns.

### React Router v5: Nested Routes with `match.path`

This pattern from [`fixtures/nesting/src/modern/App.js`](https://github.com/facebook/react/blob/main/fixtures/nesting/src/modern/App.js) uses `match.path` to build relative routes and explicitly renders a nested `<Switch>`:

```jsx
import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
} from 'react-router-dom';

function Dashboard({ match }) {
  return (
    <div>
      <h2>Dashboard</h2>
      <ul>
        <li><Link to={`${match.url}/stats`}>Stats</Link></li>
        <li><Link to={`${match.url}/settings`}>Settings</Link></li>
      </ul>

      <Switch>
        <Route path={`${match.path}/stats`} component={Stats} />
        <Route path={`${match.path}/settings`} component={Settings} />
        <Route render={() => <p>Select an option.</p>} />
      </Switch>
    </div>
  );
}

function Stats() { return <p>Stats page</p>; }
function Settings() { return <p>Settings page</p>; }
function Home() { return <h2>Home</h2>; }
function About() { return <h2>About</h2>; }

export default function App() {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
        <Route path="/dashboard" component={Dashboard} />
        <Route render={() => <h3>Page not found</h3>} />
      </Switch>
    </Router>
  );
}

```

### React Router v6: Using `<Outlet>` for Nested UI

For applications using React Router v6, the `fixtures/nesting` concepts translate to using `<Outlet>` instead of `match` objects:

```jsx
import { BrowserRouter, Routes, Route, Link, Outlet } from "react-router-dom";

function Layout() {
  return (
    <div>
      <nav>
        <Link to="/">Home</Link> | <Link to="dashboard">Dashboard</Link>
      </nav>
      <hr />
      <Outlet />
    </div>
  );
}

function Dashboard() {
  return (
    <div>
      <h2>Dashboard</h2>
      <ul>
        <li><Link to="stats">Stats</Link></li>
        <li><Link to="settings">Settings</Link></li>
      </ul>
      <Outlet />
    </div>
  );
}

export default function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Layout />}>
          <Route index element={<h2>Home</h2>} />
          <Route path="about" element={<h2>About</h2>} />
          <Route path="dashboard" element={<Dashboard />}>
            <Route path="stats" element={<p>Stats page</p>} />
            <Route path="settings" element={<p>Settings page</p>} />
          </Route>
          <Route path="*" element={<h3>Page not found</h3>} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

```

## Key Files in the React Nesting Fixture

The `facebook/react` repository includes a dedicated `fixtures/nesting` directory that demonstrates these patterns across React versions. These files illustrate how to maintain a single router context while supporting both modern and legacy React roots.

| File | Role | Link |
|------|------|------|
| [`fixtures/nesting/src/modern/App.js`](https://github.com/facebook/react/blob/main/fixtures/nesting/src/modern/App.js) | Sets up `<BrowserRouter>`, `<Switch>`, and top‑level routes (`/`, `/about`, `/dashboard/*`). | https://github.com/facebook/react/blob/main/fixtures/nesting/src/modern/App.js |
| [`fixtures/nesting/src/modern/HomePage.js`](https://github.com/facebook/react/blob/main/fixtures/nesting/src/modern/HomePage.js) | Demonstrates navigation via `<Link>` and shows that child routes must be rendered inside the parent route's component. | https://github.com/facebook/react/blob/main/fixtures/nesting/src/modern/HomePage.js |
| [`fixtures/nesting/src/modern/lazyLegacyRoot.js`](https://github.com/facebook/react/blob/main/fixtures/nesting/src/modern/lazyLegacyRoot.js) | Shows how to lazy‑load a legacy root while preserving the single router context established at the app level. | https://github.com/facebook/react/blob/main/fixtures/nesting/src/modern/lazyLegacyRoot.js |
| [`fixtures/nesting/src/legacy/createLegacyRoot.js`](https://github.com/facebook/react/blob/main/fixtures/nesting/src/legacy/createLegacyRoot.js) | Implements the same nesting concepts using the React 16.8 legacy root API. | https://github.com/facebook/react/blob/main/fixtures/nesting/src/legacy/createLegacyRoot.js |
| [`fixtures/nesting/README.md`](https://github.com/facebook/react/blob/main/fixtures/nesting/README.md) | Documents the demo's purpose and lists dependencies including `react-router-dom@5.2.0`. | https://github.com/facebook/react/blob/main/fixtures/nesting/README.md |

## Summary

- **Use a single router provider**: Wrap your application with one `<BrowserRouter>` or `<HashRouter>` at the root. Nesting additional routers breaks the shared context required for route matching.
- **Render children explicitly**: In React Router v5, parent components must render `{props.children}` or a nested `<Switch>`. In v6, use the `<Outlet>` component to display nested route elements.
- **Control matching behavior**: Add the `exact` prop to parent routes in v5 to prevent them from consuming all URLs, or order routes from most-specific to least-specific within `<Switch>` or `<Routes>`.
- **Use relative paths correctly**: Build nested paths using `match.path` and `match.url` in v5, or declare relative paths in v6 nested route definitions.

## Frequently Asked Questions

### Why does my parent route hide all my child routes?

Your parent route likely lacks the `exact` prop (in v5) or is defined with a path that matches every URL (like `path="/"`). When using `<Switch>`, the router stops at the first match. Without `exact`, the parent consumes the URL, preventing deeper routes from evaluating. Place specific routes before generic ones or add `exact` to the parent path.

### What is the difference between `match.path` and `match.url` in nested routes?

`match.path` is the route path pattern used for matching (e.g., `/dashboard/:id`), while `match.url` is the actual matched portion of the URL (e.g., `/dashboard/123`). Use `match.path` when defining nested `<Route path={`${match.path}/subroute`} />` patterns, and use `match.url` when creating `<Link to={`${match.url}/subroute`} />` navigation targets.

### Why do I need to use `<Outlet>` in React Router v6?

React Router v6 replaces the implicit `props.children` rendering pattern with an explicit `<Outlet>` component. When a parent route matches, the router looks for an `<Outlet>` in that component's render output to determine where to insert the child route element. Omitting `<Outlet>` results in a blank page even when the URL matches a nested path correctly.

### Can I use nested routes with lazy-loaded components?

Yes, but you must ensure the lazy-loaded component renders the router context correctly. As shown in [`fixtures/nesting/src/modern/lazyLegacyRoot.js`](https://github.com/facebook/react/blob/main/fixtures/nesting/src/modern/lazyLegacyRoot.js), you should define your routes and `<Switch>` or `<Routes>` inside the lazy component, but keep the `<BrowserRouter>` at the application root. Never wrap a lazy-loaded subtree with its own `<BrowserRouter>`, as this creates a disconnected routing context.