đ 2 years ago đ 15 min read đââď¸ by Madza
Search engines and users alike do not want to find a page that does not exist or is incomplete. As a developer, you should avoid it as well because it could reduce the number of repeat visits to your site and affect how highly it ranks in Google searches.
Next.js is a popular framework, that is built on top of the React library and comes with a bunch of useful built-in features, one of them being handling redirects to avoid such cases.
In this article, we will set up a Next.js app and take a closer look at different ways you can implement them in your future projects. I will also provide code snippets for both configuration files and routes and explain how they work in Next.js.
Redirects enable users to transfer an executed URL to a new URL or, to put it another way, to reroute an incoming request from one path to another. Those are usually handled by the server via HTTP redirection status codes (3xx), 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, and many other situations.
We will be using create-next-app
which is an officially supported way by Next.js to set up the development server we will use to test our redirect examples.
First, open up your terminal and run the command npx create-next-app test-app
. This will create a new project folder where all the logic of the application will live.
Next, change the working directory to the newly created folder by 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 next.config.js
file, which should be located at the root level of your product 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 the 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 /welcome
we used in the configuration. In the root level of the pages
folder, create a new file welcome.js
, and include 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 then 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, lets edit next.config.js
to this:
module.exports = { async redirects() { return [ { source: '/draft/:slug', destination: '/blog/:slug', permanent: true, }, ] }, }
To set up the routes, inside the pages
folder create two new folders named draft
and blog
and create a file article.js
inside both of them.
In the draft/article.js
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 https://localhost:3000/draft/article
and you will be redirected to 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. It is as simple as adding a *
character to the slug you are targeting in the URL.
Switch back to next.config.js
and change it to this:
module.exports = { async redirects() { return [ { source: '/draft/:slug*', destination: '/blog/:slug*', permanent: true, }, ] }, }
In order to create nested routes, we will have to make 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 the file tutorial.js
.
In the draft/react/tutorial.js
include the following code:
export default function Tutorial() { return <h1>Nested source route</h1>; }
In the blog/react/tutorial.js
include the following code:
export default function Tutorial() { return <h1>Nested destination route</h1>; }
Now restart the dev server and access https://localhost:3000/draft/react/tutorial
. You should be immediately redirected to https://localhost:3000/blog/react/tutorial
. Notice that the whole nested path got redirected.
Regex is a powerful tool that you can use to access different parts of the URL path more effectively. You will have more control over redirect behavior and will be allowed to create custom rules for redirects.
Change next.config.js
to the following code:
module.exports = { async redirects() { return [ { source: '/draft/:slug(^[a-z]+)', destination: '/blog/article', permanent: false, }, ] }, }
In the code snipped above, we configured only the routes consisting just of 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 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 https://localhost:3000/draft/article
. You will be redirected to https://localhost:3000/blog/article
since the route consists just of letters.
Now try to access https://localhost:3000/draft/article123
. You will be displayed the content of the URL you entered and not be redirected cause the route includes numbers.
Here are a couple of useful sites to help you write regex queries: regex101 and regexr.
Next.js also supports the prefix for the base path in the URL. This might be useful if you have to set multiple redirects and do not 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
, while in the second redirect object the base path got ignored since we set basePath
to false
.
With Next.js you can have even further control over redirects, 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 next.config.js
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 key
will be matched.
In the code snippet above we used header
and checked against the host
key to have 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. Now access your app on https://localhost:8000
. This time you will not be redirected since the host
value did not match your redirect configuration.
You might 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. It 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 will be successfully redirected to the all-lowercase route version. Now, remove the middleware.js
file; youâll find that youâre not able to access the all-lowercase route versions.
Next.js comes with a built-in way of handling the API calls. You can use redirect()
method to perform a redirect if the certain response is successful. This could be really handy when logging in users, submitting forms, and many other use cases.
To create a new API route, navigate to the api
folder inside pages
and create a new file 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 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, submit it and 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.
If you want to set redirects via the built-in pre-render methods of Next.js, you can include them in getStaticProps
or getServerSideProps
.
Using the getStaticProps
, the page will be pre-rendered at build time (Static site generation).
To set up an example, navigate to the root level of the pages
folder and edit index.js
:
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 Server side rendering (SSG) you would use getServerSideProps
, which will make sure Next.js pre-renders the page on each request.
To set up the SSG example, edit index.js
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
and you will 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.
In this article, we looked at a number of ways how you can 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 also took a closer look at how you can create redirects based on the received request params. Finally, we looked at how to implement redirects using the API routes and Static site generation vs Server-side rendering.
Hopefully, 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.