Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions docs/01-app/03-api-reference/03-file-conventions/not-found.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,38 @@ The `global-not-found.js` file bypasses your app's normal rendering, which means
- Your app has multiple root layouts (e.g. `app/(admin)/layout.tsx` and `app/(shop)/layout.tsx`), so there's no single layout to compose a global 404 from.
- Your root layout is defined using top-level dynamic segments (e.g. `app/[country]/layout.tsx`), which makes composing a consistent 404 page harder.

### Root layouts in a dynamic segment

The root `app/not-found.js` file also provides UI for globally unmatched URLs. If your only root layout is nested under a dynamic segment, such as `app/[lang]/layout.js`, Next.js cannot compose that global not-found route with the dynamic root layout because no `lang` value has been selected.

You can use `global-not-found.js` for a routing-level 404, or add a catch-all route inside the dynamic segment when the not-found UI needs to inherit the layout:

| | `global-not-found.js` | Catch-all route with `notFound()` |
| ------------------------------------ | ------------------------------------------------- | ------------------------------------------------------------------- |
| **Inherits the dynamic root layout** | No. Import shared styles and components directly. | Yes. The dynamic segment is resolved before `notFound()` is called. |
| **Handles** | All globally unmatched URLs. | URLs that match the catch-all route. |
| **HTTP status** | `404` | `404` for non-streamed responses and `200` for streamed responses. |

To use the localized pattern, remove the root `app/not-found.js` file, place the not-found UI at `app/[lang]/not-found.js`, and add a catch-all page that calls `notFound()`:

```tsx filename="app/[lang]/[...rest]/page.tsx" switcher
import { notFound } from 'next/navigation'

export default function UnmatchedRoute() {
notFound()
}
```

```jsx filename="app/[lang]/[...rest]/page.js" switcher
import { notFound } from 'next/navigation'

export default function UnmatchedRoute() {
notFound()
}
```

Use `global-not-found.js` when you need a global hard `404`. Use a catch-all route when rendering the not-found UI inside the dynamic root layout is more important. For streamed responses, Next.js injects a `noindex` meta tag even though the status code is `200`. See [Status Codes](/docs/app/api-reference/file-conventions/loading#status-codes) for details.

To enable it, add the `globalNotFound` flag in `next.config.ts`:

```tsx filename="next.config.ts"
Expand Down
Loading