Skip to content

Next.js Navigation

Next.js provides several ways to move between routes: the <Link> component for declarative navigation, the useRouter hook for programmatic navigation, and the redirect function for server-side redirects. This lesson covers when to use each.

The Link Component

<Link> from next/link is the primary way to navigate between routes in Next.js. It renders a real <a> tag (so it works without JavaScript and is crawlable by search engines) but intercepts clicks to perform a fast, client-side transition instead of a full page reload, and automatically prefetches the linked route's code in the background when it enters the viewport.

Because <Link> handles prefetching and client-side transitions for you, it should be your default choice for any navigation triggered by clicking — reserve useRouter for navigation that happens as a side effect of logic (like after a form submits successfully).

import Link from "next/link";

export default function Nav() {
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/blog">Blog</Link>
      <Link href="/blog/hello-world">First Post</Link>
    </nav>
  );
}

<Link> works in both Server and Client Components and requires no "use client" directive by itself.

Navigation APIs at a Glance

import Link from "next/link";                 // declarative navigation
import { useRouter } from "next/navigation";     // programmatic navigation (client)
import { redirect } from "next/navigation";      // server-side redirect
  • <Link> is a component used directly in JSX for clickable navigation.
  • useRouter() (from next/navigation, not next/router) is a hook usable only in Client Components.
  • redirect() can be called inside Server Components, Route Handlers, and Server Actions.
  • Importing from next/router instead of next/navigation is a Pages Router-only API and will not work in app/.

Navigation Cheat Sheet

Which navigation API to reach for in each situation.

Situation API to Use
A clickable link in JSX <Link href="...">
Navigate after a button's onClick logic finishes useRouter().push("...")
Go back to the previous page useRouter().back()
Redirect inside a Server Component / Server Action redirect("...") from next/navigation
Read the current pathname on the client usePathname()
Read URL query parameters on the client useSearchParams()

Programmatic Navigation with useRouter

useRouter is a client-only hook that gives you imperative control over navigation — useful when you need to redirect after some logic completes, such as after a successful login or form submission, rather than in direct response to a click on a link.

"use client";

import { useRouter } from "next/navigation";

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

  async function handleLogin() {
    await fakeLogin();
    router.push("/dashboard");
  }

  return <button onClick={handleLogin}>Log In</button>;
}

router.push() performs a client-side transition, just like clicking a <Link>.

Server-Side Redirects

redirect() from next/navigation works in Server Components, Route Handlers, and Server Actions, immediately stopping execution and sending the browser to a new location — useful for guarding routes that require authentication.

import { redirect } from "next/navigation";

export default async function DashboardPage() {
  const user = await getCurrentUser();
  if (!user) {
    redirect("/login");
  }

  return <h1>Welcome, {user.name}</h1>;
}

Common Mistakes

  • Importing useRouter from next/router (the Pages Router API) inside an app/ component.
  • Using <a> tags instead of <Link> for internal navigation, losing prefetching and client-side transitions.
  • Calling useRouter() inside a Server Component, which throws because it's a client-only hook.
  • Forgetting that redirect() throws internally to stop execution — code after it in the same function never runs.

Key Takeaways

  • <Link> is the default way to navigate declaratively; it prefetches and performs client-side transitions.
  • useRouter() (from next/navigation) enables programmatic navigation in Client Components.
  • redirect() performs server-side redirects in Server Components, Route Handlers, and Server Actions.
  • Always import navigation hooks from next/navigation, not the legacy next/router.
  • usePathname() and useSearchParams() give client-side access to the current URL's parts.

Pro Tip

Reach for <Link> first for anything the user clicks, and only drop down to useRouter().push() when navigation genuinely depends on the outcome of some asynchronous logic — this keeps your navigation code declarative and easy to follow.