`useRouter` in the App Router: Push, Replace, Refresh, and Back

useRouter gives a Client Component programmatic control over navigation. Learn push, replace, refresh, and back, and how each one changes the page.

7 min read

The useRouter hook lets a Client Component change routes in code, instead of relying on a reader clicking a link. Call it inside an event handler, such as after a button click finishes some logic or a form submits.

App.tsxApp.tsx
// app/search/search-form.tsx
"use client";
import { useRouter } from "next/navigation";
 
export default function SearchForm() {
  const router = useRouter();
  return (
    <button onClick={() => router.push("/search/results")}>View results</button>
  );
}

This hook only works in a Client Component, which is why the file starts with a client directive. Clicking the button changes the URL to the results page and swaps in the new content, the same client-side transition a plain link click triggers.

A common mistake is importing this hook from the wrong package. That older import path belongs to the Pages Router and exposes a different hook entirely, so using it inside an App Router project causes an error. Always import from next/navigation in the App Router, never from next/router.

The four methods, one at a time

Each method changes the current route differently. Pick the one that matches what the reader should actually see happen.

MethodWhat it does
pushNavigates to a new route and adds a history entry
replaceNavigates to a new route without adding a history entry
refreshRe-fetches the current route's data from the server
back() / forward()Moves through browser history like the browser's own buttons

Push and replace both accept an options object as a second argument, such as one that turns off the default scroll-to-top behavior. Neither method takes a separate path string as a second positional argument the way an older router once did.

When replace is the right call

Reach for replace instead of push when the current entry should not stay in history, such as sending a signed-in reader away from a login page after they sign in.

App.tsxApp.tsx
// app/login/redirect-button.tsx
"use client";
import { useRouter } from "next/navigation";
 
export default function GoToDashboard() {
  const router = useRouter();
  return (
    <button onClick={() => router.replace("/dashboard")}>Continue</button>
  );
}

Clicking this button sends the reader to the dashboard, and pressing the browser's back button afterward skips the login page entirely instead of returning to it. That is the visible difference between the two methods.

Getting fresh data with refresh

The refresh method re-runs the current route's data fetching and re-renders its Server Components, without a full browser reload and without losing client-side state such as an open menu or a text field's value. It is the method to reach for right after a mutation changes data the current page depends on, since navigating alone will not pick up that change.

For the exact reason navigating alone does not refresh stale data, see Why router.push() Does Not Refresh Data in Next.js. To compare this hook against server-side redirects, read useRouter vs redirect in Next.js: Client vs Server Navigation.

Rune AI

Rune AI

Key Insights

  • Import useRouter from next/navigation in the App Router, not from next/router.
  • useRouter only works in a Client Component, so its file needs the use client directive.
  • push adds a new history entry, replace swaps the current one.
  • refresh re-fetches the current route's data from the server without a full reload.
  • back and forward move through browser history the same way the browser buttons do.
RunePowered by Rune AI

Frequently Asked Questions

Why does my useRouter import not work?

You are likely importing it from next/router, which is the Pages Router hook. In the App Router, import useRouter from next/navigation instead.

Can I use useRouter in a Server Component?

No. useRouter only works in a Client Component, so the file that calls it needs the use client directive at the top.

Does push accept a second argument like the old Pages Router did?

No. The App Router version only takes a destination and an options object, not a separate path string.

Conclusion

useRouter gives a Client Component direct control over navigation. Push and replace move between routes, refresh pulls fresh server data into the current route, and back or forward move through browser history, all without a full page reload.