Capítulo 122 de 456

not-found.js

Core Idea

Duas convenções para 404: not-found.js renderiza UI quando a função notFound() é chamada dentro de um segmento de rota; global-not-found.js (experimental) define uma página 404 para toda a aplicação a nível de roteamento, para URLs que não casam com nenhuma rota, sem depender de renderizar layout/page.

Key Concepts

  • not-found.js: fica entre loading.js e page.js na hierarquia; é envolvido pelo <Suspense> de loading.js e pelo error boundary de error.js do mesmo segmento; segue o color scheme do SO (prefers-color-scheme), não lê tema da aplicação por padrão.
  • global-not-found.js: bypassa a renderização normal da app; precisa importar seus próprios estilos globais/fontes/tema (não herda layout); precisa retornar documento HTML completo (<html>/<body>); útil quando há múltiplos root layouts ou root layout com dynamic segment top-level, tornando impossível compor um 404 único via layout.js + not-found.js.
  • Ativação: global-not-found.js requer flag experimental.globalNotFound: true em next.config.ts.
  • Sem props: nem not-found.js nem global-not-found.js aceitam props.
  • Status HTTP: 200 para resposta streamed, 404 para resposta não-streamed; ambos incluem <meta name="robots" content="noindex"> automaticamente.
  • Root app/not-found.js: além de capturar notFound() chamado explicitamente, também trata qualquer URL não casada em toda a aplicação (desde v13.3.0).

Code Examples

import Link from 'next/link'

export default function NotFound() {
  return (
    <div>
      <h2>Not Found</h2>
      <p>Could not find requested resource</p>
      <Link href="/">Return Home</Link>
    </div>
  )
}
  • O que demonstra: not-found.js básico de segmento, Server Component por padrão.
import './globals.css'
import { Inter } from 'next/font/google'
import type { Metadata } from 'next'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: '404 - Page Not Found',
  description: 'The page you are looking for does not exist.',
}

export default function GlobalNotFound() {
  return (
    <html lang="en" className={inter.className}>
      <body>
        <h1>404 - Page Not Found</h1>
        <p>This page does not exist.</p>
      </body>
    </html>
  )
}
  • O que demonstra: global-not-found.js importando explicitamente estilos globais e fonte, com metadata exportado (algo não suportado em global-error.jsx, mas suportado aqui).
import { headers } from 'next/headers'

export default async function NotFound() {
  const headersList = await headers()
  const domain = headersList.get('host')
  const data = await getSiteData(domain)
  return <h2>Not Found: {data.name}</h2>
}
  • O que demonstra: not-found.js como Server Component async buscando dado (ex. por domínio via headers()); para hooks de Client Component (usePathname), o fetch precisa migrar para o client.

Anti-patterns

  • Esperar que not-found.js de segmento herde tema global: usa prefers-color-scheme do SO; para tema explícito, use regra CSS de alta especificidade com seletor de tema, ou forneça markup próprio.
  • Não importar CSS/fontes em global-not-found.js: ele bypassa a árvore normal de renderização, nada é herdado automaticamente.
  • Usar global-not-found.js sem ativar experimental.globalNotFound: feature não funciona sem a flag.
  • Usar usePathname (hook client) dentro do not-found.js Server Component: incompatível; mova o fetch de dado dependente de path para o client-side.

Reference Tables

VersionChanges
v15.4.0global-not-found.js introduzido (experimental)
v13.3.0Root app/not-found passa a tratar URLs não casadas globalmente
v13.0.0not-found introduzido

Key Takeaways

  1. Use not-found.js para 404 contextual dentro de um segmento (chamado via notFound()); use global-not-found.js só quando não dá pra compor um 404 único via layout normal (múltiplos root layouts, ou root layout com dynamic segment).
  2. global-not-found.js, diferente de global-error.jsx, suporta metadata/generateMetadata.
  3. Ambos os arquivos injetam automaticamente noindex, então SEO não é prejudicado mesmo com status 200 no streaming.

Connects To

  • File-system conventions (ch111): índice das convenções.
  • error.js (ch114): mesmo padrão de boundary automático, mas para erro em vez de 404.
  • loading.js (ch120): envolve not-found.js na hierarquia via <Suspense>.