Hirefullstack – Software Engineering & IT-Beratung aus Berlin
← Back to overview
Core 11 min read

Layouts, templates & navigation

The frame that stays while the content changes

In one sentence

A layout wraps everything below it and survives navigation – state and all. That is exactly what makes switching pages feel instant.

Header, navigation, sidebar: things that look the same across many pages. In Next.js you write them once in a layout.tsxA frame around everything below it – header, navigation, sidebar. It stays put while you navigate and keeps its state. – and they stay untouched when the page changes.

app/layout.tsx
// The root layout is mandatory. Only here do <html> and <body> live.
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <Header />
        {children}
        <Footer />
      </body>
    </html>
  );
}

Layouts nest. If app/blog/layout.tsx exists too, it wraps every blog page – and is itself wrapped by the root layout.

nesting.txt
app/layout.tsx              header + footer
  app/blog/layout.tsx       sidebar with categories
    app/blog/page.tsx       post list
    app/blog/[slug]/page.tsx  a single post

Moving from /blog to /blog/hello:
  → both layouts stay put
  → only the innermost part is swapped
Put another way

A layout is the picture frame, the page is the picture inside. Switching swaps the picture – the frame stays on the wall, along with everything attached to it.

Tip Why this is more than saved code

Because the layout stays, it keeps its state: an expanded navigation stays open, the sidebar keeps its scroll position, a video inside keeps playing. With an ordinary page load all of that would be gone.

Layout or template?

difference.txt
layout.tsx     stays put, keeps state
template.tsx   rebuilt on every navigation

Reach for a template when …
  • a fade-in animation should run every time
  • a useEffect should fire on every page change
  • state should deliberately be reset

When in doubt: layout.tsxA frame around everything below it – header, navigation, sidebar. It stays put while you navigate and keeps its state.. A template.tsxLike a layout, but rebuilt on every navigation. For things that should start over each time – a fade-in animation, say. is the exception and costs you the very advantage layouts have.

The active link

A navigation should show where you are. For that it needs the current path – which makes it a Client componentA component that runs in the browser and can therefore use state, hooks and clicks. Marked with `"use client"` at the top of the file..

app/Navigation.tsx
"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";

const items = [
  { href: "/", label: "Home" },
  { href: "/blog", label: "Blog" },
  { href: "/contact", label: "Contact" },
];

export function Navigation() {
  const path = usePathname();

  return (
    <nav>
      {items.map((i) => {
        const active = i.href === "/" ? path === "/" : path.startsWith(i.href);
        return (
          <Link key={i.href} href={i.href} aria-current={active ? "page" : undefined}>
            {i.label}
          </Link>
        );
      })}
    </nav>
  );
}
The comparison for the home link has to be exact – otherwise it would be active everywhere.
Pitfall Only the navigation is client, not the layout

A common reflex is to put "use client" in layout.tsx. That moves the entire frame into the browser. The right move: the layout stays a server component and pulls in the small navigation component.

What a layout cannot do

Reach for it when …
  • +

    Shared styling and structure

  • +

    Loading data that applies to the whole area (menu, current user)

  • +

    Setting metadata for everything below

Skip it when …
  • Reacting to the current path – a layout does not know which page sits inside it

  • Reading searchParams – only the page gets those

  • Running something on every navigation – that is what templates are for

Good to know Layouts do not re-run when you navigate

That is the whole point – but it can surprise you if a layout loads data that should differ per subpage. Such data belongs in the page, not in the frame.

In more depth: why navigation is so fast in the App Router optional

Clicking a next/linkAn internal link that prefetches its target in the background as soon as the link becomes visible. does not reload the page. Next.js fetches only the part that changes – and thanks to the layout structure it knows exactly which part that is.

sequence.txt
Link becomes visible  → target is prefetched in the background
Click                 → only the innermost part is requested
Response              → layouts stay, content is replaced
Back button           → page comes straight from the router cache

The Router cacheThe store in the browser: navigating back shows the page instantly from memory. in the browser keeps recently visited pages around for a short while. Navigating back therefore shows something instantly – occasionally something stale. After a change you clear it with router.refresh() or, more precisely, with revalidatePath / revalidateTagTargeted invalidation: after saving, refetch exactly the pages or data that are affected..

Does it stick?

4 questions on this lesson. Wrong answers show up in your stats.

Now write it yourself

Hirefullstack

Need React firepower on your team?

We have been building React and Next.js applications for clients across Germany for years – as a single expert, as reinforcement for an existing team, or as a complete Scrum team.

Talk about your project →