Capítulo 9 de 456

Caching

Core Idea

Caching armazena o resultado de fetch de dados e computações para servir requisições futuras mais rápido. Esta página cobre caching sob Cache Components (cacheComponents: true no next.config.ts); sem essa flag, ver o guia "Caching and Revalidating (Previous Model)".

Key Concepts

  • cacheComponents: true: flag em next.config.ts que habilita o modelo de Cache Components; GET Route Handlers passam a seguir o mesmo modelo de prerender das páginas.
  • use cache: diretiva que cacheia o retorno de funções/componentes assíncronos; pode ser aplicada em nível de dados (getUsers()) ou de UI (componente/página inteira).
  • cacheLife: define o tempo de vida do cache; recomenda-se sempre parear com use cache (sem ele, aplica-se o profile default implícito).
  • Cache key: argumentos e valores capturados do escopo pai da função com use cache entram automaticamente na chave, gerando entradas separadas por input diferente.
  • <Suspense>: necessário ao redor de componentes que leem dados não cacheados ou APIs de runtime (cookies, headers, searchParams, params); o fallback entra no static shell enquanto o conteúdo real é resolvido em request time.
  • connection(): chamado antes de operações não determinísticas (Math.random(), Date.now(), crypto.randomUUID()) para adiar a execução para o request time; deve ser usado dentro de <Suspense>.
  • use cache: private: variante que dá lifetime a uma função que lê cookies/headers/searchParams diretamente, permitindo que entre num prefetch.
  • Partial Prerendering (PPR): comportamento padrão do Cache Components; gera um static shell (HTML + RSC Payload) servível direto por CDN, com partes dinâmicas atrás de <Suspense>.
  • App Shell: versão do static shell reutilizável e independente de URL, usada quando params dinâmicos não são conhecidos em build time.
  • ISR (Incremental Static Regeneration): para rotas com params dinâmicos, generateStaticParams prerenderiza URLs listadas; outras URLs recebem o App Shell instantaneamente e são promovidas em background.

Code Examples

import { cacheLife } from 'next/cache'

export async function getUsers() {
  'use cache'
  cacheLife('hours')
  return db.query('SELECT * FROM users')
}
  • O que demonstra: caching em nível de dados com lifetime explícito.
import { cookies } from 'next/headers'
import { Suspense } from 'react'

async function ProfileContent() {
  const session = (await cookies()).get('session')?.value
  return <CachedContent sessionId={session} />
}

async function CachedContent({ sessionId }: { sessionId: string }) {
  'use cache'
  const data = await fetchUserData(sessionId)
  return <div>{data}</div>
}
  • O que demonstra: extrair valor de API de runtime e passá-lo como argumento para função cacheada, evitando use cache: private e mantendo o componente elegível para prefetch.
import { connection } from 'next/server'
import { Suspense } from 'react'

async function UniqueContent() {
  await connection()
  const uuid = crypto.randomUUID()
  return <p>Request ID: {uuid}</p>
}
  • O que demonstra: gerar valor único por requisição de forma explícita, adiando para request time.

Reference Tables

API usada no componenteResultado no prerender
use cache (lifetime não muito curto)resultado cacheado, incluído no static shell
<Suspense>fallback no shell, conteúdo real via stream em request time
Valores previsíveis (import, fs.readFileSync, computação pura)completam no prerender automaticamente
Valores aleatórios/timestamp sem connection()erro/insight no dev overlay (blocking-prerender-*)

Anti-patterns

  • Ler runtime API sem <Suspense>: dispara o insight "blocking-route" no dev overlay; sempre envolva o componente que usa cookies/headers/searchParams/params em <Suspense>.
  • Chamar Math.random()/Date.now()/crypto.randomUUID() direto no prerender: gera erro de build; usar connection() + <Suspense> ou cachear o resultado.
  • Destructurar params no topo do layout: bloqueia o prerender do layout inteiro; empurrar o await params para um componente filho dentro de <Suspense>.

Key Takeaways

  1. Pareie sempre use cache com cacheLife; sem isso o profile default (stale 5m/revalidate 15m/expire never) é aplicado silenciosamente.
  2. Quanto mais fundo na árvore o trabalho assíncrono estiver, maior o static shell resultante (princípio estrutural de "maximizing the static shell").
  3. use cache: private ou extrair valor de runtime API e repassar como prop são as duas formas de manter conteúdo dependente de sessão elegível para prefetch.
  4. Todo cache é escopado ao deployment: novo deploy zera entradas, mesmo as de use cache: remote, porque a cache key inclui o build id.
  5. Bots/crawlers recebem a página inteira renderizada em request time (sem static shell), então dados que só existem em build time podem quebrar para eles.

Connects To

  • Revalidating (ch010): cacheLife, cacheTag, revalidateTag, updateTag controlam quando/como o cache aqui descrito é invalidado.
  • Route Handlers (ch016): GET Route Handlers seguem o mesmo modelo de prerender quando Cache Components está habilitado.