How to Create a Custom 404 Error Page in Nextjs 13
Learn how to create a custom 404 Error page in Next.js 13 app directory to handle all unmatched URLs and for nested routes using the not-found.js file
Creating a custom 404 page in Next.js isn't as straightforward and restricted as it used to be, especially with the recent changes introduced in Next.js 13, the process has become more flexible and powerful, allowing for a more nuanced approach to handling errors and improving user experience.
In this article, we'll explore how to create a custom 404 error page that catches any unmatched URLs in your next app and then I'll show you how you can set up this error page in nested routes to display a different error page from the one on the root using the not-found.js file.
If you want to learn how to build a custom 404 page in older versions of nextjs, check out my other article on how to create a custom 404 page in nextjs .
Overview
Unlike next 12 that uses a static default 404
page, next 13 makes use of a file called not-found.js
.
According to the nextjs docs: Thenot-found.js
file is used to render UI when thenotFound
function is thrown within a route segment. (nextjs.org, 2023)
This file is a server component by default and it supports data fetching.
To get started, we'll first explore how to setup this 404 page to handle all unmatched URLs in your app:
Not-found in App Root
The root app/not-found.js
file handles all unmatched URLs for your whole application; this means users who visits a URL that does not exist on your app will be shown the UI exported by the app/not-found.js
file.
To get started, create a not-found.js
file inside your app directory. Here's a typical markup that can be used in this file:
app/not-found.tsx
import Link from "next/link";
export default function NotFound() {
return (
<main>
<h1>Error 404 😥</h1>
<p>Oops! This page was not found</p>
<Link href="/">
Return Home
</Link>
</main>
);
}
You can style this component just like every other component in nextjs. Above, I'm simply adding some styles via the global.css
file.
Once added, try visiting any route that does not exist within your app and it should redirect to this component.
Aside from creating an error route, the not-found.js
file also provides a built-in function called notFound() that triggers the not-found
component when it is called within a route segment. Let's discuss that in the next section
Not-found in Route Segments
This works by importing the notFound
module from "next/navigation"
and calling the function within the dynamic segment. Let's say you have a dynamic route that results in individual blog posts: blog/a
, blog/b
, you can catch errors within the dynamic route and display a separate not-found.js
file from the one defined in the root.
This is what the folder structure would look like:
file tree
app/
└── blog/
├── [slug]/
│ ├── page.tsx
│ └── not-found.tsx
└── page.tsx
First, we have a blog directory that contains a dynamic route (slug) for individual posts, and then the not-found.js
file that should be triggered for only the nested slug component.
Here's the markup for the nested not-found.js
file:
app/blog/[slug]/not-found.tsx
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
export default function NotFoundComponent() {
const path = usePathname();
return (
<main className="container">
<h1>{`"${path}"`} Not Found 📖</h1>
<p>Oops! We could not find this post.</p>
<Link href="/blog" className="button">
Return To Blog
</Link>
</main>
);
}
usePathname
is a Client Component hook that lets you read the current URL's path name.
To demonstrate how this will work, here's a list of links that should route to individual posts via the [slug]
parameter.
app/blog/page.tsx
import Link from "next/link";
export default function Blog() {
return (
<main>
<h1>Blog</h1>
<Link href="/blog/a">Post A</Link>
<Link href="/blog/b">Post B</Link>
<Link href="/blog/cc">Post C</Link>
</main>
);
}
Within the dynamic component, you can import the notFound
module from "next/navigation"
and call the function based on any condition of your choosing:
app/blog/[slug]/page.tsx
import Link from "next/link";
import { notFound } from "next/navigation";
export default function Post({ params }: { params: { slug: string } }) {
if (params.slug.length > 1) {
notFound();
}
return (
<div>
<h1>Post Slug: {params.slug} 📖</h1>
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Delectus,
dicta.
</p>
<Link href="/blog">
Return To Blog
</Link>
</div>
);
}
In the example above, the function is been called whenever the post slug length is greater than 1. Since /blog/cc
matches this condition, when you navigate to its URL, you will get the not-found error.
This is just an example to showcase how the notFound function works. A more valid use case for calling this function would be when a post is missing or unavailable.
Important things to note about the not-found.js component
- This component does not accept any props
- This is a server component by default but it can be converted to a client component using the
"use client"
flag. - You can mark the component as async and fetch content to display on it: Here's my example implementation that fetches my featured posts and displays them.
To test if you've been following this article, see if you can answer the following questions
What is the function of the usePathname hook
The usePathname hook is a client component hook that lets you read the current URL's path name. It can be used to display the specific path that caused the 404 error, providing more context to the user.
Conclusion
Although it is not explicit in the nextjs documentation whether the not-found.js
file is the official way of creating a custom 404 page in nextjs 13, the techniques explored in this article should serve as a good foundation. As Next.js continues to evolve, especially with the stable release of the app directory, we can anticipate further advancements and refinements, particularly in the realm of routing errors and 404 pages
I hope this article has provided valuable insights to you. If you have any questions or feedback, feel free to reach out. Happy coding!
References:
Code Files - GitHub
Nextjs. (2023). notFound. https://nextjs.org/docs/app/api-reference/functions/not-found . Functions.
Nextjs. (2023). not-found.js. https://nextjs.org/docs/app/api-reference/functions/not-found . File Conventions.
Comments