Skip to content

Nested Routes and Layouts in Next.js

In Next.js's App Router, layout.tsx files are not just for the root of your application. You can nest them to create more complex UI structures that share components across specific groups of routes. This is incredibly powerful for maintaining consistent layouts within different sections of your application, like a dashboard, an admin panel, or a user profile area.

Sharing UI Across Routes with layout.tsx Files

A layout.tsx file (or layout.js for JavaScript) defines UI that is shared across multiple pages within a particular route segment. When you create a layout.tsx inside a folder, all page.tsx files (and any nested layout.tsx files) within that folder and its subfolders will inherit that layout.

The core idea is that a layout component receives a children prop, which represents the content of the nested route segment.

Think of it like this:

app/
├── layout.tsx         // Root layout (e.g., Header, Footer)
└── dashboard/
    ├── layout.tsx     // Dashboard layout (e.g., Dashboard Sidebar, Nav)
    └── page.tsx       // Dashboard content

In this structure:

  • The dashboard/page.tsx content will be rendered inside dashboard/layout.tsx.
  • The dashboard/layout.tsx (along with the dashboard/page.tsx content) will then be rendered inside the app/layout.tsx.

This creates a hierarchical layout structure where UI elements are reused efficiently.

Creating a Dashboard Layout for Authenticated Users (/dashboard/layout.tsx)

For our Task Management App, we want a different layout for the dashboard section. The dashboard will likely have a sidebar with navigation specific to tasks, user profiles, or settings, which shouldn't appear on the public homepage.

Let's create a specific layout for our /dashboard route.

  1. Create a new file named layout.tsx inside your app/dashboard/ folder:

    my-task-app/
    └── app/
        ├── layout.tsx
        ├── page.tsx
        └── dashboard/
            ├── layout.tsx    <-- NEW FILE
            └── page.tsx
        └── globals.css
    
  2. Add the following content to app/dashboard/layout.tsx:

    app/dashboard/layout.tsx

    // app/dashboard/layout.tsx
    // This layout specifically applies to the /dashboard route and any of its nested routes.
    // It is a Server Component by default.
    
    export default function DashboardLayout({
      children, // The content of the nested page (e.g., app/dashboard/page.tsx)
    }: {
      children: React.ReactNode; // TypeScript type for children prop
    }) {
      return (
        <div className="flex flex-col md:flex-row min-h-[calc(100vh-180px)]"> {/* Adjusted min-height for better fit with root header/footer */}
          {/* Dashboard Sidebar */}
          <aside className="w-full md:w-64 bg-gray-50 p-6 shadow-md rounded-lg md:mr-6 mb-6 md:mb-0">
            <h3 className="text-xl font-semibold text-gray-700 mb-4">Dashboard Navigation</h3>
            <nav>
              <ul className="space-y-3">
                <li>
                  <a
                    href="/dashboard" // Using a simple href for now, will use <Link> later
                    className="block p-3 rounded-md text-blue-600 hover:bg-blue-100 transition duration-200"
                  >
                    All Tasks
                  </a>
                </li>
                <li>
                  <a
                    href="/dashboard/settings" // Example for future nested route
                    className="block p-3 rounded-md text-gray-700 hover:bg-gray-200 transition duration-200"
                  >
                    Settings
                  </a>
                </li>
                {/* More navigation items will be added here */}
              </ul>
            </nav>
          </aside>
    
          {/* Main content area for the dashboard */}
          <section className="flex-grow bg-white p-6 shadow-md rounded-lg">
            {children} {/* This is where app/dashboard/page.tsx (or other nested pages) will render */}
          </section>
        </div>
      );
    }
    

Summary

What we've done:

  • We've introduced a layout.tsx file inside the app/dashboard directory.
  • This DashboardLayout component now provides a common UI structure (a sidebar and a main content area) for all routes starting with /dashboard.
  • The children prop within DashboardLayout ensures that the page.tsx file (like app/dashboard/page.tsx) or any further nested routes within /dashboard will be rendered inside this layout.
  • We've used basic Tailwind CSS classes to style the sidebar and main section.

To observe the nested layout:

  1. Ensure your development server is still running (npm run dev).
  2. Open your browser and navigate to http://localhost:3000/dashboard.

You should now see your dashboard page with a distinct sidebar on the left and your "Your Dashboard" message in the main content area, all within the global header and footer. This clearly demonstrates how nested layouts provide a powerful way to manage shared UI segments in your Next.js application.

In the next section, we'll explore Dynamic Routes, which will allow us to create pages for individual tasks based on their unique IDs.