Layouts: the shared shell
Every real site repeats its chrome, the fixed framing around the content, on every page: nav bar, footer, fonts. In the React course you solved this by composing components manually on each page. Next.js formalizes it with layout.js:
// app/layout.js (the required root layout) export default function RootLayout({ children }) { return ( <html lang="en"> <body> <nav>My Site</nav> {children} </body> </html> ); }
Decode it:
- The root layout must render the
htmlandbodyelements. It replaces the oldindex.html. childrenis the current page. Navigate from/to/aboutand onlychildrenchanges.- The layout component itself does not re-render or lose state when you move between its pages.
Layouts nest
Drop another layout.js deeper in the tree and it wraps only that section:
app/
├── layout.js ← wraps everything
└── docs/
├── layout.js ← wraps only /docs/* (e.g. a sidebar)
├── page.js → /docs
└── setup/page.js → /docs/setupVisiting /docs/setup renders root layout → docs layout → the setup page, nested like Russian dolls. This is the same composition-with-children pattern from the React course, applied by the router automatically.
State inside a layout survives navigation
Picture the docs layout containing a search input with text already typed into it. A user navigates from /docs to /docs/setup. The typed text survives.
Layouts do not remount when you navigate between pages inside them. Only the page part, the children slot, is swapped out. Any state living in the docs layout, including the text in that search input, the scroll position, or an open sidebar, is untouched by the move.
That persistence is the whole point of the layout convention. It gives you a place to put state that should outlive individual pages, and it is why a Next.js sidebar does not flicker on every click.
Link: navigation without the reload
A plain <a href="/about"> works, but it triggers a full page reload: the browser throws everything away and starts over. Next.js ships a smarter component:
import Link from "next/link"; <Link href="/about">About</Link>
What Link buys you:
- Client-side navigation. Only the changing part of the tree is swapped in, and layout state survives, exactly as described above.
- Prefetching. Next.js can start loading the target page before the click, so navigation feels instant.
Rule of thumb: Link for every internal route, plain anchor tags only for external sites.
Diagnosing a theme picker that keeps resetting
Here is a bug report you will eventually see in real life. A teammate built the site nav out of plain <a href="/pricing"> tags, and users report that the theme picker in the root layout resets on every click.
The fix is to replace those anchors with the Link component from next/link.
Why it works out that way
- A plain anchor causes a full page reload, which tears down and remounts every component, root layout included, so the theme state is destroyed and recreated at its default.
Linkperforms client-side navigation instead: only the page content swaps, layouts persist, and the chosen theme survives.- Next.js ships this navigation component in
next/link, so no extra dependency is involved.
| Behaviour | Plain anchor | Link |
|---|---|---|
| Page reload | Full reload | No reload |
| Layout state | Lost | Preserved |
| Prefetching | None | Automatic |
| Use it for | External sites | Internal routes |