redirect & permanentRedirect

Programmatic navigation and the try/catch gotcha.

Next.js4 min readConcept 21 of 65

Programmatic routing

While the <Link> component handles user clicks, there are many scenarios where you need to navigate programmatically—like after a successful form submission or when an unauthenticated user tries to access a protected route.

Next.js provides the redirect() and permanentRedirect() functions from next/navigation for exactly this purpose.

Status Codes: 307 vs 308

redirect('/dashboard') issues a 307 (Temporary Redirect). This is the correct status code for actions like logging in or submitting a form, because the origin URL isn't permanently gone.

permanentRedirect('/new-url') issues a 308 (Permanent Redirect). This tells search engines that the old URL is gone forever, and they should transfer their SEO ranking to the new destination.

The throw mechanism

Here is the most critical architectural detail about redirect(): it does not return a value. Instead, it internally throws a special Next.js error.

When Next.js catches this specific error, it aborts the current render or Server Action, and immediately issues the 307/308 HTTP response back to the client.

The Throw Mechanism

Watch this automated trace showing exactly how the Next.js server executes a Server Action, hits a redirect(), and halts execution by throwing.

Auto Demo: Server Action Execution

actions.ts
export async function createPost() {
await db.insert(post);
redirect("/dashboard");
throw NEXT_REDIRECT
// Execution halts immediately!
console.log("This never runs");
}
Next.js FrameworkCatches the error
HTTP 307
Temporary RedirectLocation: /dashboard

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1Why is it dangerous to call redirect() inside a try/catch block?
  2. 2Which function should you use after a user successfully submits a 'Create Post' form?

Remember this

  • redirect() issues a 307 (Temporary) response.
  • permanentRedirect() issues a 308 (Permanent) response.
  • Both functions work by throwing an error.
  • Never call redirect() inside a try/catch block unless you explicitly re-throw it.

Done with this concept?

Mark it complete to track your progress. No login needed.