Capítulo 172 de 456

notFound

Core Idea

Lança um erro que renderiza a UI de 404 do Next.js, útil para tratar recursos ausentes; a UI é customizável via arquivo not-found.js.

Key Concepts

  • notFound(): lança NEXT_HTTP_ERROR_FALLBACK;404 e termina o render do segmento de rota onde foi chamado. Injeta <meta name="robots" content="noindex" /> automaticamente.
  • Deve ser chamado no render path: um componente, ou função awaitada por um componente. Chamada em promise não aguardada não é capturada, e nenhuma UI de not-found renderiza (log ⨯ unhandledRejection em dev).
  • Contextos suportados: Server Components, Server Functions, Route Handlers.
  • never return type: TypeScript entende que notFound() nunca retorna, então não precisa de return notFound().

Code Examples

// app/user/[id]/page.tsx
import { notFound } from 'next/navigation'

export default async function Profile({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const user = await fetchUser(id)
  if (!user) {
    notFound()
  }
}
  • O que demonstra: chamada básica quando um recurso não existe.
// notFound() dentro de Suspense, checagem na camada de acesso a dados
async function getPost(slug: string) {
  const res = await fetch(`https://api.example.com/posts/${slug}`)
  if (res.status === 404) notFound()
  if (!res.ok) throw new Error(`Failed to load post: ${res.status}`)
  return res.json()
}

async function Article({ slug }: { slug: string }) {
  const post = await getPost(slug)
  return <article><h1>{post.title}</h1></article>
}
  • O que demonstra: manter o shell da página e o loading UI visíveis enquanto o dado carrega, fazendo a checagem de existência dentro de um componente sob <Suspense>.
// app/api/posts/[slug]/route.ts
import { notFound } from 'next/navigation'

export async function GET(request: Request, { params }: RouteContext<'/api/posts/[slug]'>) {
  const { slug } = await params
  const res = await fetch(`https://api.example.com/posts/${slug}`)
  if (!res.ok) notFound()
  return NextResponse.json(await res.json())
}
  • O que demonstra: notFound() também funciona em Route Handlers, servindo 404 ao caller.

Reference Tables

VersionChanges
v13.0.0notFound introduzido

Anti-patterns

  • Chamar dentro de try/catch sem rethrow: o catch suprime a exceção e a UI de not-found não renderiza — use unstable_rethrow se precisar capturar erros perto da chamada.
  • Deixar notFound() em promise não aguardada: nada captura a exceção, UI não renderiza.
  • Esperar status 404 real após streaming ter começado: se a checagem roda dentro de um <Suspense>, a resposta já começou como 200 e o status não muda mais; para 404 real, cheque antes do stream começar (ex. em proxy com Cache Components).

Key Takeaways

  1. Não precisa de return notFound(), o never type já narrowa o TypeScript.
  2. A checagem idiomática fica na função de acesso a dados, não bloqueando o shell da página.
  3. Para status HTTP 404 real (não soft-404), a checagem precisa rodar antes do streaming iniciar.
  4. unstable_rethrow é necessário se você envolve chamadas que podem lançar notFound() em try/catch genérico.

Connects To

  • not-found.js: arquivo de convenção que define a UI customizada.
  • unstable_rethrow: necessário para deixar o erro de notFound() passar por um catch genérico.
  • forbidden / unauthorized: funções irmãs para outros códigos de erro HTTP.