C.W.K.
Stream
Lesson 04 of 10 · published

Nested Layouts

~20 min · layout, nesting, template

Level 0Curious
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

Layouts compose by folder

Each segment can declare its own layout.tsx. They nest automatically: a child layout renders inside its parent. The render tree is exactly what the folder tree looks like.

app/layout.tsx                       → wraps everything
  app/dashboard/layout.tsx           → wraps /dashboard/*
    app/dashboard/settings/page.tsx  → rendered inside both layouts

What persists, what re-renders

Navigating from /dashboard/settings to /dashboard/billing only swaps the page; both layouts stay mounted. Navigating from /dashboard/settings to /marketing/pricing unmounts the dashboard layout and mounts whatever wraps marketing.

layout.tsx vs template.tsx

Use layout.tsx by default. Use template.tsx when you need fresh state or enter/exit animations on every navigation — it re-mounts each time. The name in the folder is the only difference; the props are the same.

Code

Three-level nesting in action·tsx
// app/layout.tsx — site chrome
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en"><body>
      <SiteNav />
      {children}
    </body></html>
  );
}

// app/(app)/layout.tsx — app chrome (uses route group; URL doesn't include /(app)/)
export default function AppLayout({ children }: { children: React.ReactNode }) {
  return <div className="flex"><AppSidebar /><div className="flex-1">{children}</div></div>;
}

// app/(app)/dashboard/layout.tsx — dashboard chrome
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return <div className="p-6 space-y-4"><DashboardTabs />{children}</div>;
}

// app/(app)/dashboard/billing/page.tsx — wrapped by all three above
Use template for re-mount semantics·tsx
// app/(app)/dashboard/template.tsx — fresh instance per navigation
'use client';
import { motion } from 'framer-motion';

export default function Template({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 8 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.18 }}
    >
      {children}
    </motion.div>
  );
}

External links

Exercise

Add a third-level nested layout to the dashboard you built last lesson. Confirm with React DevTools that the parent layouts don't remount when the deepest page changes.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.