The not-found.js Convention

Specialized 404 boundaries that preserve your layout.

Next.js4 min readConcept 12 of 65

The 404 boundary

The not-found.js file is used to render a custom UI when a user requests a resource that doesn't exist.

Just like error.js and loading.js, this file is nested *inside* the layout.js of its folder. This means your 'Page Not Found' screen will still beautifully render inside your application's shell, complete with sidebars and navigation.

Beyond bad URLs

While it automatically catches users typing a bad URL, its most powerful use case is data fetching.

If a user visits /users/123, but user 123 was deleted from the database, this isn't a runtime *crash* (which belongs in error.js). It's a missing resource. You want to show a 404.

The notFound() function

You create the UI by exporting a component from not-found.js.

To trigger it manually from a Server Component (like in the deleted user scenario), you import the notFound function from next/navigation and call it. if (!user) notFound();

The 404 Bypass

Watch the auto-demo as a bad URL request drops through the component tree, completely bypassing the ErrorBoundary and landing in the NotFound boundary.

/users/99
Idle
layout.tsx
error.tsx
React Error Boundary
page.tsxData Fetch
not-found.tsx404 Boundary

Click Run Demo. When page.tsx fails to find User 99, it calls notFound(). Notice how the resulting internal error explicitly bypasses the red error.tsx boundary and gets caught by the orange not-found.tsx boundary instead.

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1How do you manually trigger a not-found.js boundary when a database query returns null?
  2. 2If you call notFound(), and the route has BOTH an error.js and a not-found.js, what happens?

Remember this

  • not-found.js renders a 404 UI *inside* the layout.
  • Trigger it manually by calling notFound() from next/navigation.
  • notFound() explicitly bypasses error.js boundaries.
  • You can have different not-found.js files for different parts of your app.

Done with this concept?

Mark it complete to track your progress. No login needed.