Skip to content
C.W.K.
Stream
Lesson 10 of 10 · published

Navigation

~20 min · Link, useRouter, redirect, prefetch

Level 0Curious
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

The Link component does more than href

<Link> performs client-side transitions, prefetches the destination route, and preserves layout state. Use it for any in-app navigation. Plain tags trigger full reloads.

Programmatic navigation

Inside Client Components, useRouter() from next/navigation lets you navigate from code. Server Components can call redirect().

The hooks you actually use

HookReturnsWhere
useRouter()Router methods (push, replace, refresh)Client
usePathname()Current pathname stringClient
useSearchParams()URLSearchParamsClient
useSelectedLayoutSegment()Active child segment of the current layoutClient

Choose navigation primitives by semantics. A destination users can open in a new tab, copy, or index is a link. A redirect caused by a successful server operation belongs in server control flow. Imperative client navigation is for behavior that is genuinely the result of an interaction, not a substitute for anchors. Prefetch is useful work only when the destination is likely to be visited. A screen with hundreds of dynamic links can spend bandwidth and server capacity on routes nobody opens. Include unclicked work when evaluating navigation performance.

Compare Link, a plain anchor, router.push, and server redirect while watching network traffic and layout mounts. Test new-tab, copy-link, and back-button behavior. The fastest click is not a win if browser conventions disappear.

Code

Link + prefetch·tsx
import Link from 'next/link';

export function Nav() {
  return (
    <nav className="flex gap-3">
      <Link href="/">Home</Link>
      <Link href="/about">About</Link>
      <Link href="/blog/hello-world">Blog</Link>
      <Link href="/dashboard" prefetch={false}>
        Dashboard (no prefetch)
      </Link>
    </nav>
  );
}
Programmatic push from a form·tsx
'use client';
import { useRouter } from 'next/navigation';
import { useTransition } from 'react';

export function LoginForm() {
  const router = useRouter();
  const [pending, start] = useTransition();

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        start(async () => {
          const ok = await login();
          if (ok) router.push('/dashboard');
        });
      }}
    >
      <button disabled={pending}>{pending ? 'Signing in&hellip;' : 'Sign in'}</button>
    </form>
  );
}
Server-side redirect with no client JS·tsx
import { redirect } from 'next/navigation';

export default async function Page() {
  const session = await getSession();
  if (!session) redirect('/login');
  return <Dashboard session={session} />;
}

External links

Exercise

Replace every <a href=…> in your app with <Link>. Add a server-side redirect on a route that requires auth, and a client-side router.push after a successful form submit.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.