Next.js App Router useRouter Guide: Client-Side Navigation, Refreshing Data, and Best Practices

The useRouter hook in the Next.js App Router is the primary API for handling client-side navigation in modern Next.js applications. It allows developers to navigate between routes, refresh server-rendered data, prefetch pages, and interact with browser history—all without triggering a full page reload.

This guide explains how routing works in the App Router using the useRouter API from next/navigation. It covers common methods such as router.push(), router.replace(), router.refresh(), and router.prefetch(), with practical examples and best practices for real-world applications.

Importing useRouter in the App Router

In the App Router, routing is managed through hooks provided by the next/navigation module. The useRouter hook replaces routing utilities from the legacy Pages Router.

import { useRouter } from "next/navigation";

Important:
Avoid importing useRouter from next/router. That module is designed for the Pages Router and does not fully support App Router features.

Client-Side Navigation with router.push()

The router.push() method performs client-side navigation without a full page reload. It also adds a new entry to the browser’s history stack, allowing users to navigate back.

"use client";

import { useRouter } from “next/navigation”;

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

return (
<button onClick={() => router.push(“/dashboard”, { scroll: false })}>
Go to Dashboard
</button>
);
}

Key behavior

  • Triggers navigation instantly

  • Preserves client-side state

  • Supports options like disabling scroll restoration

Replacing Routes with router.replace()

The router.replace() method navigates to a new route without creating a new browser history entry. This is commonly used for authentication flows, onboarding steps, or conditional redirects.

router.replace("/login");

Because the history entry is replaced, users cannot navigate back to the previous route using the browser’s back button.

Refreshing Server Data with router.refresh()

The router.refresh() method revalidates and refetches server-rendered data for the current route.

router.refresh();

What this does

  • Re-renders Server Components

  • Re-runs data fetching logic

  • Preserves client-side state and UI

This is especially useful after mutations such as form submissions or database updates.

Prefetching Routes for Faster Navigation

Prefetching loads route data before the user navigates, reducing perceived load times. The App Router supports both automatic prefetching (via <Link />) and manual prefetching using the router API.

router.prefetch("/profile");

You can also respond when prefetched data becomes invalid:

router.prefetch("/profile", {
onInvalidate: () => {
console.log("Prefetched data is stale");
},
});

Because prefetched data may become outdated, applications should decide when to re-prefetch or rely on fresh server data.

Browser History Navigation Helpers

The App Router exposes helpers for interacting directly with browser history.

router.back();
router.forward();

These methods behave the same as the browser’s back and forward buttons and do not trigger full reloads.

Security and Best Practices for App Router Navigation

When using useRouter, follow these best practices:

  • Never pass untrusted or user-generated URLs directly into routing methods

  • Prefer the <Link /> component for standard navigation and automatic prefetching

  • Be aware that caching can affect how router.refresh() behaves

  • Use router.replace() intentionally to avoid trapping users in flows

Migrating Routing Logic from the Pages Router

When migrating from the Pages Router to the App Router, routing state is no longer accessed through a single router object. Instead, Next.js provides dedicated hooks for reading route data.

import { usePathname, useSearchParams } from "next/navigation";

const pathname = usePathname();
const searchParams = useSearchParams();

The App Router also removes event-based routing APIs. Navigation is now handled declaratively as part of the framework’s core rendering model.

Final Thoughts

The useRouter hook is the foundation of client-side navigation in the Next.js App Router. It enables fast route transitions, fine-grained control over browser history, server data refreshes, and performance optimizations through prefetching.

Understanding how useRouter works and how it differs from the legacy Pages Router, helps prevent navigation bugs and ensures your Next.js applications behave predictably at scale.

Official documentation: https://nextjs.org/docs/app/api-reference/functions/use-router

Ready to Start Your Project?