`useRouter` vs `redirect` in Next.js: Client vs Server Navigation

useRouter is a client-side hook for event handlers, and redirect is a server-side function that interrupts rendering. Learn which one fits which situation.

7 min read

useRouter and redirect both move a reader to a new route in Next.js, but they run in different places and get triggered in different ways. The router hook is for a Client Component event handler, while the function can run during server rendering, inside a Server Action, or inside a Route Handler.

useRouterredirect
Runs whereClient Component, in an event handlerServer Component, Server Action, or Route Handler
Needs a client directiveYesNo
TriggerCalled manually, such as on a clickInterrupts rendering the moment it runs

How redirect actually works

Calling this function throws a special error internally that stops rendering the current route segment and sends the reader to the new path instead. Because it works by throwing, it has to be called outside a try block, or a surrounding catch clause will swallow the signal and the navigation never happens.

typescripttypescript
// app/actions.ts
"use server";
import { redirect } from "next/navigation";
 
export async function createPost(formData: FormData) {
  const title = formData.get("title");
  await savePost(title);
  redirect("/posts");
}

Submitting the form that calls this action saves the post, then sends the browser to the posts page. Wrapping the save call and this function together in one try block would catch the thrown redirect and stop the navigation from completing, which is a common mistake when writing a Server Action.

The status code redirect sends

Outside a Server Action, redirect responds with a 307 status, which preserves the original request method instead of downgrading it. Inside a Server Action, it performs a client-side navigation when JavaScript is available in the browser, and only falls back to an actual HTTP response, a 303, for a form submitted without JavaScript. A separate function, permanentRedirect, exists for the 308 case, used when a route has moved for good rather than temporarily.

Choosing between the two

Reach for the redirect function right after a mutation finishes on the server, such as inside the post-creating action above. Reach for the router hook when the navigation is triggered by something happening purely in the browser, with no server round trip involved at all.

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")}>Search</button>
  );
}

This button has no Server Action behind it, so redirect is not an option here. The click happens entirely in the browser, which is exactly the situation the router hook is built for.

The full list of methods this hook exposes, including refresh and back, is covered in useRouter in the App Router: Push, Replace, Refresh, and Back. If a page still shows stale data after a redirect, that is a caching question rather than a navigation one, covered in Why router.push() Does Not Refresh Data in Next.js.

Rune AI

Rune AI

Key Insights

  • useRouter is a Client Component hook used inside event handlers.
  • redirect is a function that can run in Server Components, Server Actions, and Route Handlers.
  • redirect works by throwing an error, so call it outside a try block.
  • redirect defaults to a 307 response outside Server Actions, and permanentRedirect uses 308.
  • Choose redirect after a mutation on the server, and useRouter after a client-side event.
RunePowered by Rune AI

Frequently Asked Questions

Can redirect be used inside a try/catch block?

It should be called outside the try block. redirect works by throwing a special error to stop rendering, and a catch block that swallows every error would swallow that signal too.

What status code does redirect use?

307 in most server contexts, which preserves the request method. During a Server Action, redirect performs a client-side navigation when JavaScript is available, and falls back to a 303 response for a form submitted without JavaScript.

Can useRouter run on the server?

No. useRouter is a Client Component hook and only works in code that runs in the browser after hydration.

Conclusion

useRouter and redirect solve navigation from opposite sides of the app. useRouter is a client-side hook for event handlers such as button clicks, and redirect is a server-side function that interrupts rendering in a Server Component, Server Action, or Route Handler before any content reaches the browser.