Saying 404 on purpose
What if /blog/does-not-exist is requested and your fetch finds no post? Rendering an empty page is wrong, and throwing shows the error boundary. The honest answer is a 404, and Next.js gives you a function for it:
import { notFound } from "next/navigation"; export default async function PostPage({ params }) { const { slug } = await params; const post = await getPost(slug); if (!post) notFound(); return <h1>{post.title}</h1>; }
Calling notFound() stops rendering and shows the nearest not-found.js file, which you write like any other special file:
// app/blog/not-found.js export default function NotFound() { return <p>That post does not exist.</p>; }
The response also carries a real HTTP 404 status, which search engines respect. You know why that matters from Backend with Node.js: status codes are the contract of the web.
Quiz
What happens when a server component calls notFound()?
Catch-all segments
One more bracket trick. [slug] matches exactly one segment. Add three dots and it matches any depth:
app/docs/[...parts]/page.js
/docs/intro→parts === ["intro"]/docs/api/auth/tokens→parts === ["api", "auth", "tokens"]
The param becomes an array of segments. Catch-alls power docs sites and wikis where the hierarchy is data, not folders. Use them sparingly. If the depth is fixed, prefer explicit folders.
Problem
With app/docs/[...parts]/page.js, a user visits /docs/guides/routing. How many strings are in the parts array?