Mastering Redirection in Next.js: A Complete Guide
Image Source: Picsum

Key Takeaways

This guide outlines essential redirection techniques for Next.js, covering the evolution from next/router to the modern App Router and Middleware. It highlights version-specific implementations for server-side, client-side, and middleware-based routing, emphasizing that server-level redirects are superior for maintaining performance, SEO integrity, and a seamless user experience.

  • Leverage the redirect function from next/navigation within Next.js 13+ Server Components to handle redirects during the initial request lifecycle.
  • Implement middleware.ts for centralized, global routing logic, ensuring absolute URLs are used to comply with Next.js 12.1+ requirements.
  • Prioritize server-side redirection via getServerSideProps or Middleware to enhance SEO and eliminate the ‘flicker’ effect common in client-side navigation.
  • Use location.replace for client-side redirects when you need to navigate the user without preserving the original page in the browser history.

Mastering Redirection in Next.js: A Complete Guide

Redirection is a crucial element in web development, facilitating smooth navigation and enhancing user experiences. Next.js, a popular React framework, provides several powerful techniques for implementing efficient redirection. This comprehensive guide will empower you with the knowledge and skills needed to master redirection in Next.js for various scenarios.

Update: Next.js >= 13 with AppDir Enabled

For Next.js versions 13 and above, equipped with the AppDir feature, you can leverage the next/navigation library for redirection. Here are examples demonstrating its usage:

In Pages:

import { redirect } from "next/navigation";

export default async function Home({ params }) {
  redirect("/hello-nextjs");
  // ...
}

In Client Components:

"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";

export const Home = () => {
  const { push } = useRouter();

  useEffect(() => {
    push("/hello-nextjs");
  }, []);
  return <p></p>;
};

Update: Next.js >= 12.1

Starting from Next.js version 12.1, relative URLs in redirects are no longer supported and will result in errors. To manage redirection efficiently:

  1. Create a middleware.ts (or .js) file at the same level as your pages directory.

  2. Export a middleware function.

  3. Create an absolute URL and utilize the redirect function.

Here’s a TypeScript example of middleware.ts:

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(request: NextRequest) {
  const url = request.nextUrl.clone();
  if (url.pathname === "/") {
    url.pathname = "/hello-nextjs";
    return NextResponse.redirect(url);
  }
}

Update: Next.js >= 12

For Next.js versions 12 and above, you can implement server-side redirects using the getServerSideProps function:

export async function getServerSideProps(context) {
  const res = await fetch(`https://.../data`);
  const data = await res.json();

  if (!data) {
    return {
      redirect: {
        destination: "/hello-nextjs",
        permanent: false
      }
    };
  }

  return {
    props: {} // will be passed to the page component as props
  };
}

Client-Side Redirects

Client-side redirection can be achieved with Next.js’s Router:

import Router from 'next/router';

componentDidMount() {
    const { pathname } = Router;
    if (pathname === '/') {
       Router.push('/hello-nextjs');
    }
}

Or using Hooks:

import React, { useEffect } from "react";
import Router from "next/router";

useEffect(() => {
  const { pathname } = Router;
  if (pathname === "/") {
    Router.push("/hello-nextjs");
  }
});

For a smoother redirect without flashing, consider this approach:

import React, { useEffect, useState } from "react";
import Router from "next/router";

const MyPage = () => {
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    const { pathname } = Router;
    // Conditional redirect
    if (pathname === "/") {
      // Using router.push may add the page to history, to prevent this:
      // Router.push('/hello-nextjs')
      location.replace("/hello-nextjs");
    } else {
      setLoaded(true);
    }
  }, []);

  if (!loaded) {
    return <div></div>; // Display nothing or a loader
  }

  return (
    <p>
      You will see this page only if pathname !== "/", <br />
    </p>
  );
};

export default MyPage;

While client-side redirection is handy, it’s advisable to handle redirects at the server level or utilize conditional component rendering for a more elegant solution.

For reference, you can explore a repository containing all the examples discussed in this article here.

The SQL Whisperer

The SQL Whisperer

Senior Backend Engineer with a deep passion for Ruby on Rails, high-concurrency systems, and database optimization.

Optimizing Asset Management in Next.js
Prev post

Optimizing Asset Management in Next.js

Next post

Effortless State Management with Redux Toolkit and TypeScript

Effortless State Management with Redux Toolkit and TypeScript