How to Redirect in Next.js?

Redirects are crucial for managing user navigation, improving user experience, and maintaining clean URL structures. In Next.js 14 App Router, you can implement redirects on the server, client, or even in middleware, depending on your needs. This tutorial will show you how to handle redirects with practical examples from a Recipe App.

Here’s the folder structure for the Recipe App, showing where server-side, client-side, and middleware-based redirects are used:

src/
└── app/
    ├── (public)/
    │   ├── layout.tsx
    │   └── recipes/
    │       ├── page.tsx       # Server-side redirect
    │       └── [id]/
    │           └── page.tsx   # Client-side redirect
    └── (admin)/
        └── recipes/
            └── add/
                └── page.tsx   # Uses client-side redirect after submission
     middleware.ts                 # Middleware for authentication and redirects

Server-Side Redirects

Server-side redirects are triggered before the page is served to the client. This is useful when you want to redirect based on conditions or move users from outdated URLs.

Use Case: Redirecting users from /recipes/all to /recipes.

You can use the redirect() function directly in a Server Component to perform server-side redirects.

// src/app/(public)/recipes/page.tsx
import { redirect } from 'next/navigation';

export default function RecipesPage() {
  redirect('/recipes'); // Redirect to the new /recipes route
  return null; // No page content needed
}

Explanation:

  • When a user visits /recipes/all, the server-side redirect() is called before the page is rendered, sending them to /recipes.
  • This is useful for permanently deprecating old URLs.

Client-Side Redirects

Client-side redirects are performed after the page is loaded, typically in response to user actions. For example, after submitting a new recipe, you might want to redirect the user to the details page for that recipe.

Use Case: Redirecting to a recipe details page after submitting a recipe.

Here’s how you can do it using the useRouter hook inside a Client Component:

// src/app/(public)/recipes/[id]/page.tsx
'use client';

import { useRouter } from 'next/navigation';
import { useState } from 'react';

export default function RecipeDetail({ params }: { params: { id: string } }) {
  const router = useRouter();
  const [formSubmitted, setFormSubmitted] = useState(false);

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    setFormSubmitted(true);
    router.push(`/recipes/${params.id}`); // Redirect to the details page
  };

  return (
    <section>
      <h2>Recipe: {params.id}</h2>
      {formSubmitted ? (
        <p>Recipe submitted! Redirecting...</p>
      ) : (
        <form onSubmit={handleSubmit}>
          <label htmlFor="recipe">Update Recipe:</label>
          <input type="text" id="recipe" />
          <button type="submit">Submit</button>
        </form>
      )}
    </section>
  );
}

Explanation:

  • Once the form is submitted, the useRouter().push() method redirects the user to the recipe details page.
  • This is an example of client-side navigation, where the user stays on the same page until an action (like form submission) triggers the redirect.

Redirects Using 'next.config.js'

Next.js allows you to define static redirects in the next.config.js file, which is great for permanent redirects that don’t need any dynamic logic.

Use Case: Redirecting from an old path to a new one.

In your next.config.js file:

// next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/old-recipes',
        destination: '/recipes',
        permanent: true, // Use true for permanent redirects (HTTP 301)
      },
    ];
  },
};

Explanation:

  • This will redirect anyone trying to access /old-recipes to /recipes with a permanent redirect.
  • This method is useful for handling URL changes across the entire app.

Redirects with Middleware

Middleware in Next.js allows you to run logic before the request is completed. It’s perfect for handling conditional redirects, such as redirecting users to a login page if they aren’t authenticated.

Use Case: Redirecting unauthenticated users from the admin section to the login page.

Here’s how you can set up middleware to handle this:

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(req: NextRequest) {
  const { pathname } = req.nextUrl;
  
  // Check if the request is for the admin section
  if (pathname.startsWith('/admin')) {
    const isAuthenticated = req.cookies.get('auth_token');

    // If the user is not authenticated, redirect to login page
    if (!isAuthenticated) {
      return NextResponse.redirect(new URL('/login', req.url));
    }
  }

  return NextResponse.next(); // Continue to the requested route if authenticated
}

export const config = {
  matcher: ['/admin/:path*'], // Apply middleware to admin routes
};

Explanation:

  • This middleware checks if the user is trying to access any admin page.
  • If the user isn’t authenticated (no auth_token in cookies), they’re redirected to /login.
  • The matcher configuration ensures that the middleware only applies to /admin routes.

Permanent vs. Temporary Redirects

Permanent and temporary redirects are important for SEO and user experience.

  • Permanent Redirect (HTTP 301): This is used when a URL has permanently moved to a new location, signaling to search engines to update their links.
  • Temporary Redirect (HTTP 302): This is used when a URL temporarily points to another location, but it may return to the original URL later.

In next.config.js, you can specify whether a redirect is permanent:

// next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/temporary-page',
        destination: '/new-page',
        permanent: false, // Temporary redirect
      },
    ];
  },
};

Explanation:

  • Use permanent: true for permanent redirects (HTTP 301) and permanent: false for temporary ones (HTTP 302).
  • Permanent redirects tell search engines to update their records, while temporary ones do not.

Using Redirect Maps

Redirect maps are particularly useful when you have many old URLs that need to redirect to new ones. You can maintain a map of old-to-new paths inside your configuration.

Use Case: Mapping old recipe URLs to new ones.

// next.config.js
module.exports = {
  async redirects() {
    const redirectMap = [
      { source: '/old-recipe-1', destination: '/recipes/1' },
      { source: '/old-recipe-2', destination: '/recipes/2' },
    ];

    return redirectMap.map(({ source, destination }) => ({
      source,
      destination,
      permanent: true, // Permanent redirect
    }));
  },
};

Explanation:

  • Redirect maps allow you to easily maintain a list of old URLs and their new destinations.
  • This is particularly useful when restructuring a website with many old pages that need to be redirected.

Summary

In this tutorial, we covered various ways to handle redirects in Next.js 14 App Router:

  • Server-side redirects: Great for managing outdated URLs before rendering the page.
  • Client-side redirects: Useful when redirecting users after actions like form submissions.
  • Redirects using next.config.js: Ideal for permanent or static redirects that don’t change dynamically.
  • Middleware redirects: Perfect for conditional logic, such as redirecting unauthenticated users.

By combining these techniques, you can ensure a smooth navigation experience across your app, while managing URL changes and user access efficiently.

Next.js
Clap here if you liked the blog