Skip to content

Next Get Started

Layouts and pages - the foundation of every Next.js App Router application

Two special files define every route in your application: layout.tsx wraps your pages with shared UI and page.tsx renders the actual content for that route. Understanding how these two files interact is non-negotiable if you want your navigation , state , and data fetching to behave predictably

layout.tsx - the persistent shell

A layout.tsx wraps all pages in its segment and below. It persists across navigations - React reuses the layout component without re-mounting it

// src/app/layout.tsx - root layout wraps every page
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'My Next App',
  description: 'Built by someone who reads docs'
}

export default function RootLayout({
  children
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <nav>
          <a href="/">Home</a>
          <a href="/about">About</a>
          <a href="/dashboard">Dashboard</a>
        </nav>
        <main>{children}</main>
        <footer>© 2026 - no secrets leaked here</footer>
      </body>
    </html>
  )
}

The root layout is mandatory. Every app needs one. It replaces the conventional _app.tsx and _document.tsx from Pages Router

Key behavior:

  • Persistent - the layout component does not unmount when navigating between pages in the same layout tree
  • Server Component - layouts are Server Components by default. Don't add "use client" unless you need interactivity
  • Metadata - export metadata object for SEO and head management

nested layouts

Layouts nest. A layout in src/app/dashboard/layout.tsx wraps only the dashboard pages

// src/app/dashboard/layout.tsx
import Sidebar from '@/components/Sidebar'

export default function DashboardLayout({
  children
}: {
  children: React.ReactNode
}) {
  return (
    <section className="flex">
      <Sidebar />
      <div className="flex-1">{children}</div>
    </section>
  )
}
src/app/
  layout.tsx           # root layout (nav + footer)
  page.tsx             # /
  dashboard/
    layout.tsx         # dashboard layout (sidebar + content)
    page.tsx           # /dashboard
    settings/
      page.tsx         # /dashboard/settings

Navigating from /dashboard to /dashboard/settings keeps the sidebar mounted. The layout doesn't re-render. That's the performance win

page.tsx - the content

A page.tsx renders the content for a specific route. It receives route parameters as props

// src/app/page.tsx
export default function HomePage() {
  return (
    <div>
      <h1>Home</h1>
      <p>This content changes when you navigate</p>
      <p>The layout stays the same</p>
    </div>
  )
}

Pages are Server Components by default. They can be async - meaning you can await data fetching directly in the component

// src/app/products/page.tsx - async server component
async function getProducts() {
  const res = await fetch('https://api.example.com/products')
  if (!res.ok) throw new Error('Failed to fetch')
  return res.json()
}

export default async function ProductsPage() {
  const products = await getProducts()

  return (
    <ul>
      {products.map((p: any) => (
        <li key={p.id}>{p.name} - ${p.price}</li>
      ))}
    </ul>
  )
}

No useEffect. No useState. No loading states. The server fetches the data , renders the HTML , and sends it to the client. That's the Server Component model

Use Next.js's Link component for client-side navigation. It prefetches linked pages in the background

import Link from 'next/link'

export default function Nav() {
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/about">About</Link>
      <Link href="/products/123">Product 123</Link>
      {/* Dynamic segments work naturally */}
    </nav>
  )
}

Link prefetches pages when they enter the viewport (or when the user hovers). This makes navigation feel instant. The prefetched data is cached and reused when the navigation completes

routing basics - useRouter

For programmatic navigation , use the useRouter hook from next/navigation

'use client'

import { useRouter } from 'next/navigation'

export default function LoginButton() {
  const router = useRouter()

  return (
    <button onClick={() => router.push('/dashboard')}>
      Go to Dashboard
    </button>
  )
}

Note the import path: next/navigation , not next/router. next/router is the old Pages Router API. next/navigation is the App Router version

Key useRouter methods:

  • router.push(path) - navigate to path
  • router.replace(path) - navigate without adding to history
  • router.refresh() - re-render the current route (useful after mutations)
  • router.back() - go back in history
  • router.prefetch(path) - manually prefetch a route

prerequisites

next_01_intro.md - you should have created your first Next.js app and understand the project structure


next → next_03_routing.md