Special files and the 404 page
Besides page.tsx and layout.tsx, Next.js recognises a few more files with special names in route folders. Each one handles its own state of the page: loading, an error, missing data. Here is an overview and the 404 page; the other files are covered in their own lessons.
Special files
| File | When it is shown |
|---|---|
page.tsx | The page content |
layout.tsx | A shared wrapper for the folder's pages |
loading.tsx | While the page loads data |
error.tsx | If rendering fails with an error |
not-found.tsx | If the page or data is not found |
route.ts | An API handler instead of a page |
Your own 404 page
Create app/not-found.tsx:
// app/not-found.tsx
import Link from 'next/link';
export default function NotFound() {
return (
<main>
<h1>Page not found</h1>
<Link href="/">Back to home</Link>
</main>
);
}Open any missing address, such as /abc — this text appears together with the header from the root layout. The server responds with status 404.
The notFound() function
In the dynamic routes lesson the post page rendered "Post not found" itself, while the server answered with status 200. It is better to call the notFound() function:
// app/posts/[slug]/page.tsx
import { notFound } from 'next/navigation';
import { getPost } from '@/lib/posts';
export default async function PostPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) {
notFound();
}
return <h1>{post.title}</h1>;
}The address /posts/abc now shows the 404 page with status 404. Code after notFound() does not run, so TypeScript knows post is no longer undefined below it.
A 404 for one section
A not-found.tsx file can also go into a section folder. Then notFound() called inside a post shows a more specific text:
// app/posts/[slug]/not-found.tsx
export default function PostNotFound() {
return <p>There is no such post. Perhaps it was deleted.</p>;
}Next.js looks for the nearest not-found.tsx, going up from the page folder to the root of app/.
Common mistake
Calling notFound() inside a try...catch. The function works by throwing a special exception, and catch intercepts it — the 404 page never appears. Call notFound() outside the try block or rethrow the error.