Redirect in Next.js from uppercase to lowercase URL

Viewed 7002

I need to redirect visitors from /Contact to /contact.

When I am doing it as described in the docs I get an infinite redirect loop.

This is what I tried:

// next.config.js
async redirects() {
    return [
        {
            source: '/Contact',
            destination: '/contact',
            permanent: true
        }
    ]
}
6 Answers

With Next.JS >=12 you can use custom middleware.

Create file named middleware.js under root folder and use this code:

import { NextResponse } from 'next/server';

const Middleware = (req) => {
  if (req.nextUrl.pathname === req.nextUrl.pathname.toLowerCase())
    return NextResponse.next();

  return NextResponse.redirect(new URL(req.nextUrl.origin + req.nextUrl.pathname.toLowerCase()));
};

export default Middleware;

The following will redirect all paths that don't exist to a lower case path. If the path is not found, it will show a 404.

import { useEffect } from 'react'
import { useRouter } from 'next/router'
import Error from 'next/error'

export default function ResolveRoute() {
  const router = useRouter()

  useEffect(() => {
    const { pathname } = router;

    if (pathname !== pathname.toLowerCase()) {
      router.push(pathname.toLowerCase())
    }
  },[router])

  return <Error statusCode={404} />
}

Putting this file name as "[route].js" in the root of your pages folder will act as a catch all (unless the page exists). This will redirect to lower case. If already ready lower case then it means the page is a 404.

Following this suggestion from Reddit https://www.reddit.com/r/nextjs/comments/hk2qmk/nextjs_routing_case_sensitivity_issue/fwt29n2?utm_source=share&utm_medium=web2x&context=3

I fixed it using the _error.js page component. Like this:

import { hasUpperCase } from '../lib/string';

...

Error.getInitialProps = ({ asPath, err, res }) => {
  const statusCode = res ? res.statusCode : err ? err.statusCode : 404;

  if (asPath && hasUpperCase(asPath)) {
    res.writeHead(307, { Location: asPath.toLowerCase() });
    res.end();
  }

  return { statusCode };
};

export default Error;

I would also prefer doing this with redirects like your example though.

When I ran into this problem, I noticed NextJS appends a trailing slash to the paths. When I looked at my network console in the browser, I saw requests with alternating status codes of 307 and 308. Once I added a trailing slash to the destination path, I saw a lot of requests with a status of 307, but still getting errors.

Once I added a trailing slash to both the source and destination paths, the redirect happened as expected:

// next.config.js
async redirects() {
    return [
        {
            source: '/Contact/',
            destination: '/contact/',
            permanent: true
        }
    ]
}

I found this helpful link that cover many solution for this issue: https://www.youtube.com/watch?v=_vSMITiXAik Solution 1:

  1. use rewirte function in your next.config.js
    return [
      {
        source: "(c|C)(o|O)(n|N)(t|T)(a|A)(c|C)(t|T)",
        destination: "/Contact", // here you need to add the exact page contact or Contact
      },
    ];
  },
  1. use the _middleware feature: inside you pages folder add a _middleware.ts file.
import { NextRequest, NextResponse } from "next/server";

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname === request.nextUrl.pathname.toLocaleLowerCase())
    return NextResponse.next();
  return NextResponse.redirect(
    `${request.nextUrl.origin}${request.nextUrl.pathname.toLocaleLowerCase()}`
  );
}

with this solution you can need to rename your page to be lowercase.

  1. use middleware feature with a folder for each page.

you need to keep the _middleware.ts the same and you need to do those steps:

  • create a folder contact all lowercase.
  • move your page inside this folder.
  • add an index.ts that point to your page. its conent should be something like this:
export { default } from "./contact";
  • rename all your page with this extension: .page.tsx or page.ts if you use typescript and .page.jsx or page.js if javascript.
  • in next.config.js you need to add this pageExtensions: ["page.tsx", "page.ts"] if you use typescript and pageExtensions: ["page.jsx", "page.js"] if you use javascript.

you need to do this for all your pages.

Here's a very elegant solution that will also carry over any search/query params:

import { NextResponse } from 'next/server';

const Middleware = (req) => {
  if (req.nextUrl.pathname !== req.nextUrl.pathname.toLowerCase()) {
    const url = req.nextUrl.clone()
    url.pathname = url.pathname.toLowerCase()
    return NextResponse.redirect(url)
  }
  return NextResponse.next();
};

export default Middleware;
Related