Next.js App Router layouts: the nesting model that changed how I build UIs
← Back
April 4, 2026React6 min read

Next.js App Router layouts: the nesting model that changed how I build UIs

Published April 4, 20266 min read

The App Router's nested layout model took me a week to fully understand, but once it clicked, I rewrote my entire routing strategy. Layouts persist across navigation — they do not remount when child routes change. This single fact enables a whole category of UIs that were awkward to build in the Pages Router.

How nesting works

app/
  layout.tsx          ← Root layout (wraps everything, never unmounts)
  page.tsx            ← Home page
  dashboard/
    layout.tsx        ← Dashboard layout (persists while in /dashboard/*)
    page.tsx          ← /dashboard
    analytics/
      layout.tsx      ← Analytics sub-layout
      page.tsx        ← /dashboard/analytics
    settings/
      page.tsx        ← /dashboard/settings

Navigating from /dashboard/analytics to /dashboard/settings does NOT remount the dashboard layout. Only the page component changes.

Authenticated dashboard with sidebar

typescript
// app/dashboard/layout.tsx
import { redirect } from 'next/navigation';
import { getSession } from '@/lib/auth';

export default async function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  // Auth check runs ONCE for all dashboard routes
  const session = await getSession();
  if (!session) redirect('/login');

  return (
    
{/* Sidebar persists — no remount between dashboard routes */}
{children}
); }

Keeping sidebar state through navigation

Because the layout does not remount, state in layout components persists across navigation. This is powerful for sidebars:

typescript
'use client';

export function Sidebar({ user }: { user: User }) {
  const [collapsed, setCollapsed] = useState(false);
  const pathname = usePathname();

  // collapsed state persists through /dashboard/analytics -> /dashboard/settings navigation
  // because this component never remounts

  return (
    
  );
}

Route groups for organization without URL segments

text
app/
  (marketing)/          ← Route group — () means no URL segment
    layout.tsx          ← Marketing layout (nav + footer)
    page.tsx            ← /
    about/
      page.tsx          ← /about
    pricing/
      page.tsx          ← /pricing
  (app)/                ← Different layout for app
    layout.tsx          ← App layout (sidebar, auth)
    dashboard/
      page.tsx          ← /dashboard
    profile/
      page.tsx          ← /profile
typescript
// app/(marketing)/layout.tsx — marketing site layout
export default function MarketingLayout({ children }: { children: React.ReactNode }) {
  return (
    <>
      
      {children}
      
); } // app/(app)/layout.tsx — app layout (completely different) export default async function AppLayout({ children }: { children: React.ReactNode }) { const session = await getSession(); if (!session) redirect('/login'); return (
{children}
); }

Templates vs layouts

If you need to reset state on every navigation (unlike layouts which persist), use a template.tsx instead:

typescript
// app/dashboard/template.tsx
// This DOES remount on every navigation — unlike layout.tsx
// Use when you need fresh state per route visit

export default function DashboardTemplate({ children }: { children: React.ReactNode }) {
  // Fresh mount means fresh state, fresh effects, fresh animations
  return (
    
      {children}
    
  );
}

The mental model shift

In the Pages Router, I thought of pages as independent units. In the App Router, I think of the URL as selecting a position in a layout tree. Most of the UI is persistent layouts; only the innermost page component changes. This model maps better to how users actually experience navigating through an app — the chrome is stable, the content changes.

Share this
← All Posts6 min read