Skip to content

Remix Nested Routes — Layouts and Route Hierarchy

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about Remix Nested Routes. We cover key concepts, practical examples, and best practices to help you master this topic.

Learn Remix nested routes: parent layouts with Outlet, automatic data nesting, and building complex route hierarchies with shared UI across your app.

In this lesson, you'll build nested route layouts, understand how Remix nests loaders and data, and create complex page hierarchies.

What You'll Learn

How nested layout routes work, share UI between routes, nest loaders for efficient data fetching, and build tab-based navigation.

Why It Matters

Nested routes let each segment of a URL independently load its own data and render its own UI. This keeps page transitions fast because only the changed content re-renders.

Real-World Use

DodaZIP's admin panel uses nested routes for user management: the parent loads the user list, and child routes load details, settings, and activity without re-fetching the list.

flowchart TD
    A["/dashboard"] --> B[Nav Sidebar]
    A --> C[]
    C --> D["/dashboard/analytics"]
    C --> E["/dashboard/reports"]
    C --> F["/dashboard/settings"]
    style A fill:#121212,color:#fff

Parent Route

app/routes/dashboard.tsx:

import { Outlet, Link } from "@remix-run/react";

export default function Dashboard() {
  return (
    <div className="dashboard-layout">
      <aside>
        <Link to="analytics">Analytics</Link>
        <Link to="reports">Reports</Link>
        <Link to="settings">Settings</Link>
      </aside>
      <main>
        <Outlet />
      </main>
    </div>
  );
}

Child Route

app/routes/dashboard.analytics.tsx:

export default function Analytics() {
  return <h1>Analytics Dashboard</h1>;
}

Output: At /dashboard/analytics, the parent renders the sidebar, and the child renders the heading inside <Outlet />. Navigating to /dashboard/reports only swaps the child content.

Nested Loaders

Parent loader runs once; child loader runs independently:

// dashboard.tsx
import { json } from "@remix-run/node";
import { useLoaderData, Outlet } from "@remix-run/react";

export const loader = async () => {
  return json({ user: { name: "Alice", role: "admin" } });
};

export default function Dashboard() {
  const { user } = useLoaderData<typeof loader>();
  return (
    <div>
      <p>Welcome, {user.name}</p>
      <Outlet />
    </div>
  );
}
// dashboard.analytics.tsx
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";

export const loader = async () => {
  return json({ visitors: 1234, pageViews: 5678 });
};

export default function Analytics() {
  const data = useLoaderData<typeof loader>();
  return <p>Visitors: {data.visitors}</p>;
}

Both loaders run in parallel, and their data is available in their respective components.

Shared Error Boundaries

Nested routes can each have their own error boundary:

// dashboard.reports.tsx
export function ErrorBoundary({ error }) {
  return <p>Reports error: {error.message}</p>;
}

An error in the reports child doesn't affect the parent dashboard layout.

Common Mistakes

  1. Not nesting loaders properly: Parent and child loaders run independently. Don't duplicate parent data in child loaders.
  2. Forgetting <Outlet /> in layout routes: Without <Outlet />, child routes don't render anything inside the layout.
  3. Hardcoding paths in nested links: Use relative paths in <Link to="child"> instead of <Link to="/dashboard/child"> to make Refactoring easier.
  4. Putting too much in the parent loader: Parent loaders should only load data needed by the parent layout. Child-specific data goes in child loaders.

Practice Questions

  1. What component renders child routes inside a parent? Answer: <Outlet />. It marks where child route content is injected.

  2. Do parent and child loaders run sequentially or in parallel? Answer: In parallel. Remix fetches data for all matching route segments simultaneously.

  3. How do you add an error boundary to a nested route? Answer: Export an ErrorBoundary function from the child route module.

  4. What happens to the parent layout when navigating between children? Answer: The parent stays mounted. Only the child content inside <Outlet /> changes.

Challenge

Build a settings page with three tabs (profile, security, notifications) as nested routes under /settings. The parent should render the tab navigation and the child should render the tab content.

Mini Project

Create a user dashboard with nested routes for profile, activity log, and billing. Each child route should have its own loader and error boundary.

FAQ

Can I nest routes more than two levels deep?

: Yes. Remix supports unlimited nesting depth, though 3-4 levels is the practical maximum.

Do nested routes share data between parent and child?

: Yes. Use useRouteLoaderData("routes/dashboard") in child routes to access parent loader data.

Can I use nested routes with the `meta` export?

: Yes. Each route can export its own meta function for SEO metadata.

How does Remix handle scroll position with nested routes?

: Remix preserves scroll position when the parent URL segment doesn't change.

What's Next

Learn about Remix Layouts for sharing UI structure across unrelated routes.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro