Cache Mais Inteligente no Next.js: Renderização Parcial e Componentes Reutilizáveis
Você construiu uma aplicação Next.js com App Router. As requisições de dados funcionam. As páginas renderizam. Mas você não tem certeza se sua estratégia de cache está correta—ou se você sequer tem uma. Você viu dados desatualizados aparecerem inesperadamente, observou a mesma consulta ao banco de dados disparar várias vezes por requisição e se perguntou por que algumas rotas parecem lentas apesar de serem “estáticas.”
Este artigo explica como o cache de dados do App Router do Next.js realmente funciona, como as três camadas de cache interagem, e como construir componentes de servidor reutilizáveis que encapsulam tanto a busca de dados quanto a política de cache. Também abordaremos o Partial Prerendering do Next.js e como a renderização parcial do React 19 habilita estratégias de cache no nível de componente.
Principais Conclusões
- O Next.js usa três camadas de cache (Data Cache, Full Route Cache, Router Cache) que se cascateiam durante as requisições
- Os componentes devem possuir sua própria política de cache usando
cache()do React para deduplicação e opções de fetch para controle de tempo de vida - A revalidação baseada em tags permite invalidação cirúrgica de cache em múltiplas rotas
- O Partial Prerendering (PPR) permite misturar shells estáticos com conteúdo dinâmico em streaming através de limites de Suspense
Como as Três Camadas de Cache Funcionam Juntas
O cache do Next.js opera através de três mecanismos distintos que interagem durante cada requisição.
Data Cache
O Data Cache persiste resultados de fetch entre requisições e deployments. Quando você chama fetch com cache habilitado, o Next.js armazena a resposta no lado do servidor. Requisições subsequentes retornam dados em cache até que a revalidação ocorra.
// Em cache por 1 hora em todas as requisições
const posts = await fetch('https://api.example.com/posts', {
next: { revalidate: 3600 }
})
Full Route Cache
No momento do build, o Next.js renderiza rotas estáticas em HTML e payloads RSC. Este Full Route Cache serve conteúdo pré-renderizado instantaneamente. Rotas puramente dinâmicas ignoram este cache, mas rotas com segmentos estáticos ou revalidação ainda podem gerar shells estáticos.
Client-side Router Cache
O navegador armazena payloads RSC em memória durante a navegação. Layouts persistem entre mudanças de rota. Rotas visitadas são armazenadas em cache na memória durante a sessão e reutilizadas durante a navegação até serem invalidadas.
Essas camadas se cascateiam: invalidar o Data Cache afeta requisições subsequentes, e o Full Route Cache ou Router Cache são atualizados na próxima renderização que requer dados atualizados.
Construindo Componentes de Servidor Reutilizáveis com Cache
O modelo mental que previne bugs de dados desatualizados: componentes devem possuir sua própria política de cache.
// lib/data.ts
import { cache } from 'react'
export const getProduct = cache(async (id: string) => {
const res = await fetch(`https://api.example.com/products/${id}`, {
next: { revalidate: 300, tags: ['products', `product-${id}`] }
})
return res.json()
})
Esta função pode ser chamada de qualquer componente—layout, página ou filho aninhado. O cache() do React deduplica chamadas dentro de um único passe de renderização. A opção next.revalidate controla o tempo de vida do Data Cache. Tags permitem invalidação cirúrgica.
Use esta função em qualquer lugar sem prop drilling:
// app/products/[id]/page.tsx
export default async function ProductPage({ params }: { params: { id: string } }) {
const { id } = await params
const product = await getProduct(id)
return <ProductDetails product={product} />
}
Moldando o Comportamento do Cache com Opções de Segmento de Rota
Além das opções de fetch, configurações de segmento de rota controlam o cache no nível da rota:
// Força renderização dinâmica
export const dynamic = 'force-dynamic'
// Define período de revalidação para todos os fetches
export const revalidate = 3600
Para invalidação sob demanda, use revalidatePath ou revalidação baseada em tags:
// app/actions.ts
'use server'
import { revalidateTag } from 'next/cache'
export async function updateProduct(id: string) {
// await db.product.update(...)
revalidateTag(`product-${id}`)
}
Discover how at OpenReplay.com.
Partial Prerendering do Next.js: A Direção Experimental
O Partial Prerendering do Next.js representa uma mudança significativa. Em vez de escolher entre rotas totalmente estáticas ou totalmente dinâmicas, o PPR pré-renderiza um shell estático enquanto faz streaming de conteúdo dinâmico através de limites de Suspense.
import { Suspense } from 'react'
export default async function ProductPage({ params }: { params: { id: string } }) {
const { id } = await params
return (
<>
{/* Shell estático - pré-renderizado */}
<Header />
<ProductInfo id={id} />
{/* Buraco dinâmico - streaming no momento da requisição */}
<Suspense fallback={<CartSkeleton />}>
<UserCart />
</Suspense>
</>
)
}
As porções estáticas são servidas instantaneamente. Seções dinâmicas fazem streaming conforme são resolvidas. Este recurso ainda é experimental—habilite-o via ppr: true nas opções experimentais do seu next.config.js—mas aponta para o futuro do cache no Next.js.
React 19 e Cache no Nível de Componente
O comportamento aprimorado do Suspense no React 19 permite estratégias de cache mais granulares. Componentes envolvidos em Suspense podem gerenciar independentemente seu ciclo de vida de dados. Usando as APIs experimentais use cache e cacheLife, você pode fazer cache de subárvores de componentes em vez de páginas inteiras:
import { cacheLife } from 'next/cache'
async function BlogPosts() {
'use cache'
cacheLife('hours')
const res = await fetch('https://api.example.com/posts')
const posts = await res.json()
return <PostList posts={posts} />
}
A revalidação baseada em tags permite que equipes compartilhem dados em cache com segurança entre rotas. Um componente de produto usado tanto em /products/[id] quanto em /checkout pode ser invalidado uma vez, atualizando em todos os lugares.
Conclusão
Construa componentes de servidor que encapsulam sua política de cache. Use cache() do React para deduplicação de requisições, opções de fetch para controle do Data Cache, e tags para invalidação entre rotas. O Partial Prerendering é experimental, mas vale a pena entender—é para onde o cache do Next.js está caminhando.
O objetivo não é o máximo de cache. É um cache previsível que corresponde aos requisitos reais de atualização dos seus dados.
Perguntas Frequentes
O cache() do React deduplica chamadas de função dentro de um único passe de renderização, prevenindo que os mesmos dados sejam buscados múltiplas vezes durante uma requisição. O cache de fetch do Next.js persiste resultados entre múltiplas requisições e deployments usando o Data Cache. Use ambos juntos: cache() para deduplicação em tempo de renderização e opções de fetch para persistência entre requisições.
Use revalidateTag quando precisar invalidar dados específicos em múltiplas rotas, como informações de produto exibidas tanto na página de detalhes quanto na de checkout. Use revalidatePath quando quiser invalidar todos os dados em cache para um caminho de URL específico. Tags oferecem controle mais cirúrgico enquanto paths são mais simples para invalidação de rota única.
Verifique a saída do build para indicadores de rota. Rotas estáticas mostram um ícone de círculo enquanto rotas dinâmicas mostram um símbolo lambda. Você também pode adicionar declarações console.log em seus componentes—se eles logarem em cada requisição, a rota é dinâmica. Usar cookies(), headers() ou searchParams automaticamente opta as rotas para renderização dinâmica.
O Partial Prerendering ainda é experimental a partir do Next.js 15. Embora você possa habilitá-lo para testes, ainda não é recomendado para aplicações em produção. A API e o comportamento podem mudar em versões futuras. Monitore a documentação do Next.js e as notas de lançamento para atualizações de estabilidade antes de adotá-lo em produção.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.