NextjsLinking & Navigation

Linking & Navigation

Getting users from one route to another sounds simple, but how you do it in a Next.js App Router app matters a lot for performance and user experience. This lesson is an overview of the tools available; the next few lessons go deep on each one.

The Two Main Navigation Tools

Tool

Use Case

<Link> component

Declarative navigation from JSX — the default choice for links.

useRouter() hook

Programmatic navigation triggered by code — after a form submit, a timer, an event handler.

We'll cover Link in full detail next, and useRouter right after that. For now, the important thing is knowing they exist and roughly when each applies.

Why Not Just Use <a> Tags?

A plain HTML anchor tag works for navigating to another site, but for internal navigation within your own Next.js app, it throws away almost everything the framework gives you.

Warning
A native <a> tag causes a full page reload: the browser tears down the entire page, re-downloads the HTML/CSS/JS, and re-runs your React app from scratch. Any client state is lost, and the transition feels noticeably slower than a client-side navigation.

TSX
// Avoid for internal links:
<a href="/dashboard">Dashboard</a>

// Prefer:
import Link from 'next/link'
<Link href="/dashboard">Dashboard</Link>
Why Client-Side Navigation Matters

Next.js's router intercepts navigations to routes within your app and handles them on the client, without a full document reload. Instead of re-fetching an entire HTML document, it fetches only the data and component output the new route actually needs, and swaps it into the existing page.

  • The browser tab does not flash white or reload — the transition feels instant.

  • Shared layouts are preserved rather than torn down and rebuilt.

  • Next.js can prefetch routes ahead of time, so the click itself has almost nothing left to do.

  • Client-side state outside the changed segment (scroll position, open modals, form drafts) survives.

Note
Under the hood, this is powered by React's Suspense-based streaming plus the Next.js router cache. You don't need to configure any of it — using Link or useRouter gets you these benefits automatically.
A Quick Preview

TSX
// Declarative: put a Link wherever a user might click to navigate
import Link from 'next/link'

export function NavBar() {
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/blog">Blog</Link>
    </nav>
  )
}

// Programmatic: navigate as a side effect of code running
'use client'
import { useRouter } from 'next/navigation'

export function LoginButton() {
  const router = useRouter()
  return (
    <button onClick={() => router.push('/dashboard')}>
      Log in
    </button>
  )
}

Keep this rule of thumb going forward: if a user is clicking something that visually looks like a link, reach for Link. If navigation needs to happen as a result of logic — after a successful form submission, an authentication check, or a timeout — reach for useRouter instead.