Is your Next.js site getting larger, and URLs are getting out of hand? How can you ensure URL consistency, observe editors’ changes and issue proper redirects if URL slugs change?
In my previous article, I explained how URL building works and why it’s important to preserve old URLs when they change. I also introduced a custom element for Kontent.ai that you can directly plug into your project and track all URL slug changes. However, the last bit of the proposed solution does not work in some cases in the newest version of Next.js, so in this article, I will show you a more robust and functional way of handling URLs and redirects for all rendering modes of Next.js.
The future-proof way of handling URLs
There are three components to the successful handling of URLs on any website project:
Building URLs to content in the website implementation
Observing URL slug changes
Implementing a robust redirection mechanism
Building URLs to content in the website implementation
A good content platform allows you to link content items without using URLs. Just like the link at the top of this article is not defined by using a URL but links to the other content item directly.
Not using URLs directly helps a lot with consistency as the platform can warn an editor when they’re about to delete a content item other items reference, but also ensures usable linking of items among multiple channels.
URLs are tightly coupled with the website implementation and type of content:
Website home
Type of content
Content item
https://kontent.ai
/blog
/how-to-handle-url-redirects-with-headless-cms
The consistency of URLs is a vital component of any website, and as such, it should be centralized to minimize the potential for editor and developer errors. For example, this is how we handle it:
We use this map of URL structure to generate any URL to any content with no exceptions:
This has multiple benefits:
You can’t experience situations when a URL to a blog post is correct on one page but is not working on another.
You quickly find missing URL structures as the build fails with a meaningful message in that case.
The structure of the content (how an editor thinks about content and builds it) is not directly dependent on URL structure (how content is displayed on the website) which is a major benefit on larger sites and the basic concept of headless architecture.
You easily find unused content types, which helps to keep your project organized.
Observing URL slug changes
When an editor creates and publishes a page, the search engines index the URL, and from that moment on, we must ensure it always exists. I explained the problem in detail in my previous article, so here I’ll just summarize the solution.
In Kontent.ai, you can use a custom element for keeping track of URL slug changes:
It watches over the URL slug field, and when it gets changed, it automatically stores the previous value. In code, you get both the current URL slug and the history:
Implementing a robust redirection mechanism
Now that we get all the information from the content platform, we can switch to the Next.js implementation.
Here, the problem is that handling the redirect on the page level is not working for pre-built pages. Let’s take blog posts as an example:
Current URL slug
History
Blog post 1
blog-post-1
Blog post 2
blog-post-2
shiny-blog-post
You see, before building the site, we have the knowledge of all the slugs of all the blog posts, including the history. Therefore, we want to use the fallback: false mode, which instructs Next.js to pre-build everything. We hand over all the slugs, including the history, to the getStaticPaths method as that defines the existing paths:
URL slug
blog-post-1
blog-post-2
shiny-blog-post
So far so good. But when we get to getStaticProps, we need to handle the redirect:
URL slug
Render a page?
blog-post-1
yes
blog-post-2
yes
shiny-blog-post
no -> redirect to blog-post-2
We can use this code to redirect from getStaticProps to another page:
But because we’re using the fallback: false mode, all pages in the blog are being resolved during build time, and we’ll get the following error:
Error: 'redirect' can not be returned from getStaticProps during prerendering
The reason is that Next.js does not allow prerendering pages that just redirect somewhere. The best practice is to handle these redirects in next.config.js.
Solution 1: Switch mode to fallback: Blocking
You can solve this problem by switching the mode to fallback: 'blocking’, which accepts any URL slug and attempts to render a page during runtime, but it comes with three disadvantages:
You need to exclude the history URL slugs from getStaticPaths so that Next.js won’t try to render them during pre-building.
You need to handle 404 cases, so your getStaticProps implementation must first verify the URL slug to see if a page should exist at all.
The page resolution for all slugs except the ones provided in getStaticPathshappens at runtime.
This can be a nice workaround for small to medium size websites but not an ultimate solution to the problem.
Solution 2 (Better): Pre-build the redirects
If we know all the historic slugs before running a build, why waste runtime resources on resolving them?
Next.js has a redirects mechanism; the only problem is that it requires the list of URLs in next.config.js prior to running a build:
Fortunately, the redirects section is a function, so we can pre-build all the URLs into a JSON file and load it in the config. We’ll do this in five steps:
I described the pre-build scripts in another article, so here we’ll just focus on adding the actual functionality.
First, we’ll load the historic URL slugs. Because we’re generating the redirects file for the whole site, we need to handle all used content types here. This is tricky as the codenames of relevant elements may vary among content types. The best practice is to keep the URL slug and URL slug history elements’ codenames consistent among your content model - we use url_slug and url_slug_history, respectively. In that case, we can fetch the data using a single Kontent.ai query:
Note: You can adjust codenames of both content types and their elements either in the platform UI or via API
Then, we need to transform the data into the Next.js accepted structure:
Note that we need to JSON.parse the element value as it’s a JSON encoded array. Then, depending on the used URL building mechanism, we need to build the source and destination URLs from the slugs. On our site, we’re using the function displayed at the beginning of this article – getUrlPathByContentType – which finds the relevant record in the URLs map by content type.
Then, we save the list to a physical file:
This is the full pre-build script code for reference:
When you run the pre-build script, it fetches the old URL slugs and generates the /static/redirects.json file that looks like this:
Finally, we implement the redirects() function to load that JSON file in the next.config.js:
When you run the next build, Next.js will load the redirects from the /static/redirects.json file and issue proper redirects on runtime.
Conclusion
In this article, I explained the three components of future-proof URL handling on large Next.js sites. I outlined the problems with redirects on pre-generated sites and provided a robust solution for handling redirects in an automated way using pre-build scripts. With this code in place, your application is ready for URL slug changes and ensures your pages keep their ranks.
If you’re building a Next.js site with Kontent.ai, join our community on Discord to discuss your experience and get help from fellow developers (including me :-)).
Table of contents
The future-proof way of handling URLs
Building URLs to content in the website implementation
Observing URL slug changes
Implementing a robust redirection mechanism
Conclusion
Subscribe to the Kontent.ai newsletter
Get the hottest updates while they’re fresh! For more industry insights, follow our LinkedIn profile.