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.
| useRouter | redirect | |
|---|---|---|
| Runs where | Client Component, in an event handler | Server Component, Server Action, or Route Handler |
| Needs a client directive | Yes | No |
| Trigger | Called manually, such as on a click | Interrupts 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.
// 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/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
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.
Frequently Asked Questions
Can redirect be used inside a try/catch block?
What status code does redirect use?
Can useRouter run on the server?
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.
More in this topic
`generateMetadata` Explained with Real Examples
What generateMetadata does, when it runs, and how to use it for real routes: awaited params, deduplicated data fetching, extending parent metadata, and returning a 404 from metadata.
Canonical URLs in Next.js: `metadataBase`, `alternates.canonical`, and Dynamic Pages
How canonical URLs work in the Next.js App Router: setting metadataBase once, writing alternates.canonical per route, handling dynamic segments, and what happens when the base URL is missing.
Open Graph and Twitter Card Metadata in Next.js
How to write Open Graph and Twitter card metadata in the Next.js App Router: the openGraph and twitter fields, automatic card defaults, article tags, and image merge rules.