Navigate with <Link>

next/link keeps layouts mounted; template.tsx remounts.

From next-best-practices, functions.md and file-conventions.md.

<a> reloads, <Link> swaps

Press +1, type a filter, then switch pages.

<a href="/reports">Bad
<Link href="/reports">Good
// Bad: a new document, layout state lost
<a href="/reports">Reports</a>

// Good: client transition, layout kept
import Link from 'next/link'

<Link href="/reports">Reports</Link>

layout.tsx vs template.tsx

Type a draft, press +1, then navigate.

layout.tsxKeeps state
template.tsxRemounts
// app/(app)/template.tsx
export default function Template({ children }: { children: React.ReactNode }) {
  return <div className="enter">{children}</div>
}

Active link from usePathname()

Type a path or pick one.

usePathname() → /reports/q3

Exact matchBad
pathname === href
Segment matchGood
pathname.startsWith(`${href}/`)
'use client'

import Link from 'next/link'
import { usePathname } from 'next/navigation'

export function NavLink({ href, children }: { href: string; children: React.ReactNode }) {
  const pathname = usePathname()
  const active = href === '/'
    ? pathname === '/'
    : pathname === href || pathname.startsWith(`${href}/`)

  return (
    <Link href={href} aria-current={active ? 'page' : undefined} className={active ? 'active' : ''}>
      {children}
    </Link>
  )
}

Why it matters, pros and cons

Why it matters

A plain <a> loads a new document. <Link> swaps only what changed.

Pros

  • Layout state survives: counters, inputs, scroll.
  • No blank frame; links prefetch in production.
  • template.tsx scopes per-route entrance effects.

Cons

  • External sites and downloads still need a plain <a>.
  • Prefetch costs bandwidth on link-heavy pages.
  • Kept state can leak between routes; reset with key.