• Homeright=arrow
  • Blogright=arrow
  • How to Handle Redirects in Next.js
featureImage

How to Handle Redirects in Next.js

A redirect is a way to send users and search engines to a URL different from the one originally requested. In other words, you redirect the user or search engine from one URL to another.

Redirects In Next.js

In Next.js, redirects are configured in the next.config.js file using the redirects function. This allows you to define URL redirects with status codes for client and server-side routing, enhancing SEO and ensuring users effortlessly reach the correct content.

How to Handle Redirects in Next.js?

To use redirects in Next.js, you need to define them in the next.config.js file. Here is a step-by-step guide:

  • Open the next.config.js file.
  • Add a “redirects” function to your next.config.js file. This function returns an array of redirect objects.
  • Each redirect object should include source, destination, and permanent properties.

source: The incoming request path pattern.

destination: The path you want to route to.

permanent: A boolean indicating the type of redirect. If true, it uses a 308 status code (permanent redirect, cached). It uses a 307 status code (temporary redirect, not cached) if false.

module.exports = {
async redirects() {
return [
{
source: '/old-page', // The old URL
destination: '/new-page', // The new URL
permanent: true, // This will trigger a 301 redirect
},
{
source: '/temporary-page',
destination: '/new-temporary-page',
permanent: false, // This will trigger a 302 redirect
},
// Add more redirects as needed
]
},
}

In this example:

  • A request to /old-page will be permanently redirected to /new-page.
  • A request to /temporary-page will be temporarily redirected to /new-temporary-page.

Apart from these source, destination, and permanent properties, you may need to include some other properties such as basePath, localehas, and missing in redirects. Let’s Discuss these in detail also:

  • basePath: (Optional) If false, the base path won't be included when matching. Used for external redirects. When using basePath support with redirects in Next.js, both the source and destination URLs are automatically prefixed with the basePath.
module.exports = {
basePath: '/docs',

async redirects() {
return [
{
source: '/with-basePath', // automatically becomes /docs/with-basePath
destination: '/another', // automatically becomes /docs/another
permanent: false,
},
{
// does not add /docs since basePath: false is set
source: '/without-basePath',
destination: 'https://example.com',
basePath: false,
permanent: false,
},
]
},
}
  • locale: (Optional) If false or undefined, the locale won't be included when matching.
  • has: (Optional) An array of objects specifying conditions that must be met for the redirect to occur.
  • missing: (Optional) An array of objects specifying conditions that must be missing for the redirect.

Note: 

  • Next.js uses 307 and 308 status codes for redirects instead of 301 and 302.By using 307 for temporary redirects and 308 for permanent redirects, Next.js actually ensures that the original request method is maintained during the redirect.
  • In Page router, redirects will not be applied on client-side routing. We have to use Middleare to match the path.

Path Matching

Next.js redirect support path matching as well as wildcard path matching. For example, /old-blog/:slug will match /old-blog/hello-world.

module.exports = {
async redirects() {
return [
{
source: '/blog/:slug',
destination: '/news/:slug', // Matched parameters can be used in the destination
permanent: true,
},
]
},
}

However, This will not match nested paths. To solve this problem we can use wildcard path matching. To match a nested path use after a parameter. For Example, /blog/:slug will match all the nested paths inside the blog folder such as /blog/a/b/c/d/hello-world:

module.exports = {
async redirects() {
return [
{
source: '/blog/:slug*',
destination: '/news/:slug*', // Matched parameters can be used in the destination
permanent: true,
},
]
},
}

Furthermore, we can also match the path using regex. To use a regex path matching, we have to wrap the regex in parentheses after a parameter, for example, /post/:slug(\\d{1,}) will match /post/123 but not /post/abc.

module.exports = {
async redirects() {
return [
{
source: '/post/:slug(\\d{1,})',
destination: '/news/:slug', // Matched parameters can be used in the destination
permanent: false,
},
]
},
}

(, ), {, }, :, *, +, ? are used for regex. So, when these characters are used as non-special values, we must have to add a \\ before them to be escaped. An example is given below:

module.exports = {
async redirects() {
return [
{
// this will match `/english(default)/something` being requested
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
permanent: false,
},
]
},
}

Header, Cookie, and Query Matching

In Next.js, we can create dynamic redirects that use header, cookie, and query parameter matching to redirect users conditionally. This allows you to tailor the redirect behaviour based on the presence or absence of specific headers, cookies, or query parameters.

To initiate a redirect based on header, cookie, or query matches, use the has and missing fields. The redirect applies only if all has conditions match and all missing conditions do not.

The has and missing items can have the following fields:

  • type: String - must be either header, cookie, host, or query.
  • key: String - the key from the selected type to match against.
  • value: String or undefined - the value to check for. If undefined, any value will match. A regex-like string can be used to capture a specific part of the value. For example, if the value is first-(?<paramName>.*) and the matched value is first-second, then second will be usable in the destination with :paramName.
module.exports = {
async redirects() {
return [
// if the header `x-redirect-me` is present,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
has: [
{
type: 'header',
key: 'x-redirect-me',
},
],
permanent: false,
destination: '/another-page',
},
// if the header `x-dont-redirect` is present,
// this redirect will NOT be applied
{
source: '/:path((?!another-page$).*)',
missing: [
{
type: 'header',
key: 'x-do-not-redirect',
},
],
permanent: false,
destination: '/another-page',
},
// if the source, query, and cookie are matched,
// this redirect will be applied
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// the page value will not be available in the
// destination since value is provided and doesn't
// use a named capture group e.g. (?<page>home)
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
permanent: false,
destination: '/another/:path*',
},
// if the header `x-authorized` is present and
// contains a matching value, this redirect will be applied
{
source: '/',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
permanent: false,
destination: '/home?authorized=:authorized',
},
// if the host is `example.com`,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
has: [
{
type: 'host',
value: 'example.com',
},
],
permanent: false,
destination: '/another-page',
},
]
},
}

Redirects with i18n support

Next.js Redirects also supports i18n. By default, each source and destination is automatically prefixed with locales. To disable this, we need to set locale: false in the redirect configuration and manually prefix the source and destination for correct matching. This ensures accurate handling of multilingual redirects. An example is given below:

module.exports = {
i18n: {
locales: ['en', 'fr', 'de'],
defaultLocale: 'en',
},

async redirects() {
return [
{
source: '/with-locale', // automatically handles all locales
destination: '/another', // automatically passes the locale on
permanent: false,
},
{
// does not handle locales automatically since locale: false is set
source: '/nl/with-locale-manual',
destination: '/nl/another',
locale: false,
permanent: false,
},
{
// this matches '/' since `en` is the defaultLocale
source: '/en',
destination: '/en/another',
locale: false,
permanent: false,
},
// it's possible to match all locales even when locale: false is set
{
source: '/:locale/page',
destination: '/en/newpage',
permanent: false,
locale: false,
},
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
destination: '/another',
permanent: false,
},
]
},
}

That’s all. For more information, you can visit the official next.js page here.

Finally, Next.js redirects efficiently manage URL changes, SEO, and user experience. By leveraging options like basePath, locale, and conditional matching (has, missing), you can create precise, dynamic redirects that maintain request methods and cater to specific contexts, enhancing site functionality and navigation.


Want to add redirects to your existing site? Contact StaticMania. Our dedicated team will help you every step of the way to handle redirects in Next.js.

footer-particlefooter-particlefooter-particlefooter-particlefooter-particle
back-to-top