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.
You can now navigate confidently between routes. Next, take a closer look at how pages themselves are structured and composed.