Editor’s note: This post was updated Oyinkansola Awosan on 26 February 2024 to discuss changes relevant to redirects in Next.js 14 and the App Router, demonstrate how to troubleshoot common redirection issues in Next.js, and more.
Search engines and users alike don’t want to find incomplete or nonexistent pages. As a developer, you should avoid this situation as well because it could reduce the number of repeat visits to your site and affect how the site is indexed by search engines.
Next.js is a popular framework built on top of the React library that comes with a bunch of useful built-in features, one of them being handling redirects to avoid such cases.
In this article, we’ll set up an app and take a closer look at different ways you can implement redirects in your Next.js projects. I will also provide code snippets for both configuration files and routes and explain how they work in Next.js.
Let’s get started.
Redirects enable users to transfer an executed URL to a new URL — in other words, to reroute an incoming request from one path to another. These are usually handled by the server via a group of 3XX
HTTP redirection status codes, which can also be understood by web crawlers.
Redirects are frequently used in situations where a section of the site does not exist or is under construction, content has been moved to a different URL, the routing system has changed, users are being redirected due to access restrictions, or many other situations.
We’ll be using create-next-app
to set up the development server we will use to test our redirect examples. This setup method is officially supported by the Next.js team.
First, open up your terminal and run the following command:
npx create-next-app test-app
This will create a new project folder where all of the application’s logic will live.
Next, change the working directory to the newly created folder by running cd test-app
and then run npm run dev
to start the development server. Then, open your browser and navigate to https://localhost:3000
to view the live preview of the app.
The most common way to create redirects in Next.js is to use the next.config.js
file, which should be located at the root level of your project structure. If it’s not, create one and include the following code:
module.exports = { async redirects() { return [ { source: '/', destination: '/welcome', permanent: true, }, ] }, }
In the snippet above, the source
property is the requested route, destination
is the route we want to redirect the user to, and permanent
controls whether or not we want the redirect route to be cached for the client machine and search engines.
Let’s create a new route for /welcome
, which we used in the configuration. In the root level of the pages
folder, create a new file called welcome.js
and add the following code:
export default function Welcome() { return <h1>Welcome page</h1>; }
Now, restart the development server by pressing Ctrl+C
on your keyboard and run npm run dev
to start it again. This is necessary for the changes we made in next.config.js
to take effect. Remember to do this for further examples in the article as well.
To test the redirect, open your browser and navigate to https://localhost:3000
again. You should now be automatically redirected to https://localhost:3000/welcome
.
Next.js supports accessing the slugs of the URL and configuring redirects for them. For this example, let’s edit the next.config.js
file like so:
module.exports = { async redirects() { return [ { source: '/draft/:slug', destination: '/blog/:slug', permanent: true, }, ] }, }
To set up the routes, go inside the pages
folder and create two new folders named draft
and blog
, and then create the file article.js
inside both of them.
In the draft/article.js
file, include the following code:
export default function Article() { return <h1>Source route</h1>; }
In the blog/article.js
, include the following code:
export default function Article() { return <h1>Destination route</h1>; }
After restarting the dev server, try accessing the following URL:
https://localhost:3000/draft/article
You should be redirected to this URL:
https://localhost:3000/blog/article
The slug can be any supported value in the URL unless you create a route for it and do not nest it on multiple levels.
To redirect nested routes, you can use wildcards, which will essentially take all of the paths after the last known level and redirect to the new route. This redirection method is as simple as adding an asterisk *
character to the slug you are targeting in the URL.
Switch back to the next.config.js
file and change it to this:
module.exports = { async redirects() { return [ { source: '/draft/:slug*', destination: '/blog/:slug*', permanent: true, }, ] }, }
To create nested routes, we have to set up a couple of subfolders inside the draft
and blog
folders. Let’s just assume we want to categorize articles via technologies, so we will call both folders react
. Inside both newly created folders, add a file named tutorial.js
.
In the draft/react/tutorial.js
file, include the following code:
export default function Tutorial() { return <h1>Nested source route</h1>; }
In the blog/react/tutorial.js
file, include the following code:
export default function Tutorial() { return <h1>Nested destination route</h1>; }
Now, restart the dev server and access the following URL:
https://localhost:3000/draft/react/tutorial
You should be immediately redirected to this URL:
https://localhost:3000/blog/react/tutorial
Notice that the whole nested path was redirected.
Regex is a powerful tool that you can use to access different parts of the URL path more effectively. You’ll have more control over redirect behavior and will be allowed to create custom rules for redirects.
Change the contents of the next.config.js
file to the following code:
module.exports = { async redirects() { return [ { source: '/draft/:slug(^[a-z]+)', destination: '/blog/article', permanent: false, }, ] }, }
In the code snippet above, we configured only the routes consisting of the a
to z
characters being redirected to the /blog/article
route, which we created earlier.
Navigate to the draft
folder in your project structure and create a new file called article123.js
with the following code in it:
export default function Article123() { return <h1>Source route</h1>; }
To test the regex query, restart the dev server and try to access the following URL:
https://localhost:3000/draft/article
You will be redirected to this URL, since the route only contains letters:
https://localhost:3000/blog/article
Now try to access this URL:
https://localhost:3000/draft/article123
You should see the content of the URL you entered and not be redirected because the route includes numbers.
If you need any help writing regex queries, regex101 and regexr are useful resources.
Next.js also supports redirects via the prefix for the base path in the URL. This might be useful if you have to set up multiple redirects and don’t want to repeatedly write the base path for all your routes.
Change the next.config.js
to the following code:
module.exports = { basePath: '/content', async redirects() { return [ { source: '/draft/article', destination: '/blog/article', permanent: true, }, { source: '/draft/react/tutorial', destination: '/blog/react/tutorial', basePath: false, permanent: true, }, ] }, }
In the first redirect object, the source became /content/draft/article
and the destination /content/blog/article
. In the second redirect object, the base path was ignored since we set basePath
to false
.
With Next.js, you can have even further control over redirects by accessing host, header, cookie, and query values. Using the has
field, you can write custom rules to control whether the redirect should be performed in different cases.
Change the contents of the next.config.js
file to the following code:
module.exports = { async redirects() { return [ { source: '/', has: [ { type: 'header', key: 'host', value: 'localhost:3000', }, ], permanent: false, destination: '/welcome', }, ]; }, }
The type
must be either header
, cookie
, or query
. The key
must be a string from the selected type to match against. The value
is optional and if it is undefined, any values of the key
will be matched.
In the code snippet above, we used header
and checked against the host
key to get the localhost:3000
value. If these values are met in the request, the redirect will be made.
Restart the dev server and try to access https://localhost:3000
. You will be redirected to https://localhost:3000/welcome
, since the host
value matched.
Now close the dev server with Ctrl+C
and run npm run dev -- -p 8000
. This will start your application on a different port. Then, access your app on https://localhost:8000
. This time you will not be redirected since the host
value did not match your redirect configuration.
Next.js comes with a built-in way of handling API calls. You can use the redirect
method to perform a redirect if a certain response is successful. This can be really handy when logging in users, submitting forms, and other use cases.
To create a new API route, navigate to the api
folder inside pages
and create a new file called data.js
with the following code:
export default async function handler(req, res) { console.log(`Name: ${req.body.name}`); try { // some await stuff here res.redirect(307, '/welcome'); } catch (err) { res.status(500).send({ error: 'Error while fetching data' }); } }
Then, navigate to the root level of the pages
folder and create a new file called form.js
to create the form itself. Include the following code in the newly created file:
export default function Form() { return ( <form action='/api/data' method='post'> <label htmlFor='name'>Your name:</label> <input type='text' id='name' name='name' /> <button type='submit'>Submit</button> </form> ); }
Now open your browser and navigate to https://localhost:3000/form
. You will be presented with the input field to enter your name and submit button to send the value to the API. Enter any value and submit it — you should be redirected to https://localhost:3000/welcome
.
To make sure the API received the value you entered, switch back to the terminal and check the printed logs. The value should be displayed there.
You may be wondering how to redirect from uppercase URLs to lowercase URLs in Next.js. For example, let’s say you want to redirect a user from /About
to /about
. Using the standard redirect solution with source: '/About', destination: '/about'
will not work, because redirects are not case sensitive.
To solve this issue, you can use Next.js middleware. Middleware in Next.js enables you to execute code prior to a request being processed, allowing you to alter the response and redirect the user as necessary.
Create the middleware.js
file inside the root direction of the project and include the following code:
import { NextResponse } from "next/server"; const Middleware = (req) => { if (req.nextUrl.pathname === req.nextUrl.pathname.toLowerCase()) return NextResponse.next(); return NextResponse.redirect( `${req.nextUrl.origin + req.nextUrl.pathname.toLowerCase()}` ); }; export default Middleware;
To test it out, try capitalizing any previously created routes. You should be successfully redirected to the all-lowercase route version. If you remove the middleware.js
file, you’ll find that you’re not able to access the all-lowercase route version.
getStaticProps
and getServerSideProps
If you want to set redirects via Next’s built-in pre-render methods, you can include them in getStaticProps
or getServerSideProps
. The option you use will depend on whether you’re working with server-side rendering (SSR) or static site generation (SSG).
Using getStaticProps
will pre-render the page at build time (SSG). To set up an example, navigate to the root level of the pages
folder and edit the index.js
file:
export default function Home() { return <h1>Home page</h1>; } export async function getStaticProps() { const content = null; if (!content) { return { redirect: { permanent: false, destination: '/welcome', }, }; } return { props: {}, }; }
Similarly, for SSR, you would use getServerSideProps
, which will make sure Next.js pre-renders the page on each request.
To set up the SSR example, edit the index.js
file as shown below:
export default function Home() { return <h1>Home page</h1>; } export async function getServerSideProps() { const content = null; if (!content) { return { redirect: { permanent: false, destination: '/welcome', }, }; } return { props: {}, }; }
To test either of the two cases, try accessing https://localhost:3000
. You should be automatically redirected to https://localhost:3000/welcome
since the redirect rules in getStaticProps
or getServerSideProps
were executed.
In full-stack development, you‘ll often want to restrict user access to private URLs (those that require authentication to be viewed). In these cases, you’ll want to redirect the user back to the login screen.
First, let’s look at how to authenticate statically generated pages, where the user is fetched from the client side.
Start by creating a new route that will be protected. Next, create a new file, profile.js
, in the root of the pages
directory and include the following code:
import useUser from '../hooks/useUser'; const Profile = () => { const user = useUser(); if (!user) return null; return <h1>Hello, {user}</h1>; }; export default Profile;
Then, navigate to the src
directory and create a new folder, hooks
, with a useUser.js
file inside and include the following code:
import { useEffect } from "react"; import Router from "next/router"; export function useUser() { const user = false; useEffect(() => { if (!user) Router.push("/"); }, [user]); return user; }
For this tutorial, we created a sample variable for the user. In a real-life scenario, you would probably use something like swr to make an API call to check if there is an active session.
Now, try to access the /profile
route. You’ll be redirected to the /
route since there is no active user.
Next, change the user
value to some string name and try accessing the /profile
route again. You should have full access to the greeting for the value you chose.
In Next.js, we can also authenticate server-rendered pages. You can use the getServerSideProps
function, which will return the data from the server when pre-rendering pages on each request.
To try this out, update the profile.js
file with the following code:
const Profile = ({ user }) => { return <h1>Hello, {user}</h1>; }; export function getServerSideProps() { const user = false; if (!user) { return { redirect: { destination: "/", permanent: false, }, }; } return { props: {user}, }; } export default Profile;
Notice that the active user would be fetched on the server side. For this tutorial, we used a user variable to define if a logged in user is present.
To see the redirect working, try to access the /profile
route. You’ll be redirected to /
since no active user is available in the application.
Now, change the user
valuable to some name string and try to access the /profile
route again. You’ll have full access to the greeting for the string value you chose since it got passed from the server via props.
Next.js 14 was released in October 2023, and it came with new updates like support for Turbopack, partial pre-rendering, and some other features. However, there were no updates mainly related to redirects.
The only remotely related update is that you have to define a function in the React component and use server actions instead of manually creating an API route for server-side code. In one network roundtrip, you can compose and reuse many actions, including mutating data, re-rendering the page, redirecting, and more.
That being said, it’s good to be aware of the similarities and differences between redirects in the Pages Router compared to the App Router introduced in Next.js 13. Their similarities include:
push
and replace
To understand their differences, you can refer to the table below:
Features | App Router redirects | Pages Router redirects |
---|---|---|
Usage | Used for server-side redirects or client-side redirects outside of page transitions. | This is typically used for routing-related redirects and controlling the initial page load experience. |
Flexibility | More flexible due to server-side control. It can also redirect based on any condition and supports different redirect types. | Limited flexibility as user actions trigger it. |
Data-fetching | It can be combined with data fetching functions like getServerSideProps or custom hooks to fetch data before the redirect occurs. | Usually, it does not involve direct data fetching. The redirected page might have data-fetching logic. |
Server-Side Rendering (SSR) | It can redirect before the page is rendered on the server, improving SEO and performance. | It cannot redirect before SSR, as redirects are usually applied after the rendered page. |
While setting up redirects in Next.js, there are a few common errors you may encounter. Let’s explore what causes these errors and how you can troubleshoot them.
NEXT_REDIRECT
This error usually occurs when a redirect is triggered on the client side, but the redirect is not adequately set up to catch and manage the operation. The actual error message might look something like this:
Unhandled Runtime Error Error: Failed to load script: /_next/static/chunks/pages/about.js
To solve this problem, ensure that your redirect logic in API routes or client-side scripts is encapsulated within try...catch
blocks to handle any potential errors gracefully.
Also, when using next/router
for client-side redirects, confirm that the destination path is correctly formatted and the application state is in a condition that won’t cause unexpected behavior.
Suppose you’re experiencing issues with redirects not functioning as expected in API routes. In that case, it might be due to incorrect usage of the res.redirect()
method or attempting to perform a redirect after the response has already been sent:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
If you encounter this error, verify that you’re using the correct syntax for res.redirect()
by providing the status code (e.g., 307 for temporary redirects) and the destination URL.
Also, make sure to call res.redirect()
before any response is sent back — res.send()
or res.json()
— to avoid attempting to modify the response after it has been finalized.
NEXT_REDIRECT
error: Handling redirect loopsRedirect loops occur when a redirected URL, directly or indirectly, leads back to the original URL, causing an infinite loop. This can happen due to misconfigured redirect rules or logic not accounting for certain user states or request parameters.
When this happens, the browser may display some sort of error message. An example of a browser error message would be:
ERR_TOO_MANY_REDIRECTS
Carefully review your redirect rules in next.config.js
and any dynamic redirect logic in your application to identify and resolve circular patterns.
Also, utilize conditional logic to ensure redirects are only performed when appropriate, considering the current URL, user authentication state, or other relevant criteria to break out of potential loops.
When a redirect points to a missing page or a route that doesn’t exist, users might encounter a 404 error. Providing a fallback or ensuring all redirect destinations are valid can enhance the user experience.
You should implement a custom 404 page that gracefully handles missing routes and potentially guides users back to valid parts of your application. Ensure you regularly audit your redirect destinations, especially after changing your routing structure, to ensure all redirects lead to existing pages.
Also, consider using dynamic routing and getServerSideProps
or getStaticProps
to programmatically determine redirect behaviour based on content or resources, providing a fallback URL if the intended destination is unavailable.
In this article, we looked at a several ways to implement redirects in Next.js. First, we used next.config.js
and wrote custom configurations for predefined routes, accessed single-level and nested routes, and used regex to increase the control of redirects.
Then, we took a closer look at how you can create redirects based on the received request parameters and also redirect uppercase routes to lowercase routes. Lastly, we investigated how to implement redirects using the API routes, static site generation, and server-side rendering, as well as how to redirect routes that require authentication.
To further our understanding of redirects in Next.js, we explored how redirects have changed in Next.js 14 and in the Pages Router vs. the App Router. We also covered some common redirection issues in Next.js and potential ways to solve them.
I hope with this article you learned something new, and from this point onward you will be able to create redirects for all of your use cases in your future Next.js apps. If you have any further questions, feel free to comment below.
Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your Next.js app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your Next.js apps — start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowMatcha, a famous green tea, is known for its stress-reducing benefits. I wouldn’t claim that this tea necessarily inspired the […]
Backdrop and background have similar meanings, as they both refer to the area behind something. The main difference is that […]
AI tools like IBM API Connect and Postbot can streamline writing and executing API tests and guard against AI hallucinations or other complications.
Explore DOM manipulation patterns in JavaScript, such as choosing the right querySelector, caching elements, improving event handling, and more.