Pages, Layouts and Templates

beginner
10 min

Pages, Layouts and Templates

Real applications repeat UI everywhere: the same header on every page, the same sidebar across a dashboard. The App Router turns this repetition into a first-class concept with layouts. In this lesson you will learn how pages and layouts nest, why layouts preserve state during navigation, and when to reach for a template instead.

Pages: The Unique Part of a Route

A page is the UI that is unique to a URL. It is always the default export of page.js:

jsx
// app/dashboard/page.js export default function DashboardPage() { return <h1>Dashboard Overview</h1>; }

Pages are Server Components by default, so they can fetch data directly - more on that in Lessons 6 and 7.

Layouts: Shared UI That Persists

A layout wraps a page and every route below it. Add a layout.js to a folder and it receives the nested content as the children prop:

jsx
// app/dashboard/layout.js import Sidebar from './Sidebar'; export default function DashboardLayout({ children }) { return ( <div style={{ display: 'flex' }}> <Sidebar /> <section>{children}</section> </div> ); }

Now /dashboard, /dashboard/settings, and any other nested route all render inside this sidebar shell automatically.

The Root Layout

Every app has exactly one required root layout at app/layout.js. It must render the html and body tags, and it replaces the old _document and _app files from the Pages Router era. Global CSS, fonts, and site-wide providers belong here.

How Layouts Nest

Layouts compose from the outside in. For the URL /dashboard/settings, Next.js renders:

text
RootLayout └── DashboardLayout └── SettingsPage

Each folder contributes its layout if it has one. You never wire this up manually - the file system does it.

The Killer Feature: State Preservation

When a user navigates from /dashboard to /dashboard/settings, the DashboardLayout does not re-render or remount. Only the page part changes. That means:

  • A search input typed into the sidebar keeps its value.
  • A playing video in the layout keeps playing.
  • Expensive layout data is not refetched.

This partial rendering is a major performance and UX win over full-page swaps.

Templates: When You Want a Fresh Start

Occasionally you want layout-like wrapping that does remount on every navigation - for example, to replay an enter animation or reset per-page state. That is what template.js is for:

jsx
// app/dashboard/template.js 'use client'; import { motion } from 'framer-motion'; export default function Template({ children }) { return ( <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }}> {children} </motion.div> ); }

A template sits between the layout and the page. Use layouts by default; reach for templates only when remounting is the actual goal.

Different Layouts for Different Sections

Combine layouts with route groups from Lesson 3 to give site sections completely different shells:

text
app/ ├── (marketing)/ │ ├── layout.js ← header + footer │ └── pricing/page.js └── (app)/ ├── layout.js ← sidebar shell └── dashboard/page.js

Both sections share the root layout but nothing else. The URLs stay clean: /pricing and /dashboard.

Key Takeaways

  • page.js is the unique UI of a route; layout.js wraps it and all nested routes.
  • The root layout is mandatory and owns the html and body tags.
  • Layouts persist across navigation, preserving state and avoiding refetches.
  • template.js remounts on every navigation - useful for animations and reset logic.
  • Route groups plus layouts let different site sections have different shells.

Next up: Lesson 5 shows how users actually move between these routes with the Link component and programmatic navigation.

Pages, Layouts and Templates - Next.js | CodeYourCraft | CodeYourCraft