Routing and navigation

Create pages and layouts

Turn folders into URL segments and use layouts for interface that should persist while child routes change.

A folder inside app becomes a public route only when it contains a special route file such as page.tsx. A layout.tsx wraps every page below its segment.

Create app/notes/page.tsx for /notes. Add app/notes/layout.tsx when all note routes share navigation or structure. Layouts preserve state across client navigation and receive the active child as children. A plain reusable component does not get that lifecycle for free.

The root layout is required and owns the document’s <html> and <body> elements. Nested layouts should express persistent route structure: navigation, a workspace shell, or a sidebar shared by descendants. Do not promote a component to a layout just to avoid an import.

Persistence shows up during client navigation. A nested layout is not remounted as its child page changes, so local client state inside that layout can survive. A full browser reload creates a new document and resets it. Design with that lifecycle in mind.

// app/notes/layout.tsx
export default function NotesLayout({ children }: { children: React.ReactNode }) {
  return (
    <section>
      <h1>Field notes</h1>
      {children}
    </section>
  )
}

Add /notes and the layout above. Put a tiny client counter inside the layout, then create two child pages such as /notes and /notes/new. Navigate between them with Link: the counter value should stay. Hit reload: the counter resets to zero. That difference is the layout lifecycle in action.

If you put the same counter in page.tsx instead of the layout, navigation between sibling pages will reset it every time. That is the signal you picked the wrong file for persistent UI chrome.

Root layout changes affect every route. Keep it thin: document shell, fonts, and providers belong here, not feature-specific data fetching for one section.

Lesson completed