A layout is shared UI that wraps multiple pages and persists across navigation — it doesn't re-render or lose state when you move between child routes. You define one with a layout.tsx file.
The root layout (required)
() {
(
);
}
Every App Router app must have a root layout — it replaces the old _app.tsx/_document.tsx.
Layouts nest along the folder structure, so each section can add its own persistent wrapper:
app/layout.tsx → wraps everything (header/footer)
app/dashboard/layout.tsx → wraps all /dashboard/* pages (adds a sidebar)
app/dashboard/settings/page.tsx → rendered inside BOTH layouts
// app/dashboard/layout.tsx — only wraps dashboard routes
export default function DashboardLayout({ children }) {
return (
<div className="flex">
<Sidebar /> {/* stays mounted as you move within /dashboard */}
<main>{children}</main>
</div>
);
}
When you navigate from /dashboard/settings to /dashboard/billing, the dashboard layout (and its <Sidebar>) stays mounted — its state (scroll position, open menus, form input) is preserved, and only the page content swaps. This is more efficient and gives a smoother UX than re-rendering the whole shell.
// template.tsx — like layout but RE-mounts on every navigation (fresh state each time)
Use template.tsx instead of layout.tsx on the rare occasion you want the wrapper to reset per navigation.
Layouts are how the App Router models shared, persistent UI (headers, sidebars, nav) at any level of the route tree.
Their persistence across navigation — preserving state and avoiding re-renders of the shell — is a core App Router advantage, and nested layouts let each section compose its own structure cleanly.