Cache Components no Next.js 16 em 2026: use cache, PPR e Perguntas de Entrevista
Análise aprofundada dos Cache Components do Next.js 16: a diretiva use cache, Partial Pre-Rendering (PPR), cacheLife, cacheTag e perguntas de entrevista técnica para desenvolvedores seniores.

Next.js 16 trouxe uma mudança radical na forma como aplicações React gerenciam cache e renderização. Com a introdução do Cache Components e Partial Prerendering (PPR), desenvolvedores agora podem criar aplicações que combinam a velocidade de sites estáticos com a dinamicidade de aplicações em tempo real. A diretiva "use cache" permite controle granular sobre o que deve ser armazenado em cache, enquanto PPR possibilita a entrega instantânea de shells estáticos enquanto dados dinâmicos são carregados progressivamente. Dominar essas funcionalidades não é apenas uma vantagem técnica, mas um diferencial decisivo em entrevistas técnicas para vagas que envolvem Next.js em 2026.
Next.js 16 passa de um cache implícito (tudo é cacheado, opt-out com APIs dinâmicas) para um cache explícito (nada é cacheado, opt-in com "use cache"). Essa única mudança afeta o roteamento, o data fetching, a renderização e como as perguntas de entrevista são formuladas.
Por que o Next.js 16 substituiu o cache implícito
O modelo de cache implícito do Next.js 14-15 causava problemas de previsibilidade. Uma chamada fetch dentro de um Server Component era automaticamente deduplicada e cacheada, mas determinar se uma página era estática ou dinâmica dependia de quais APIs ela utilizava. Depurar o comportamento do cache exigia compreender múltiplas camadas ocultas: o fetch cache, o full-route cache e o router cache.
O Next.js 16 remove os três caches implícitos. Cada página é renderizada dinamicamente a cada requisição, a menos que seja explicitamente marcada com "use cache". O export revalidate desaparece. O unstable_cache é substituído pela diretiva "use cache" gerenciada pelo compilador.
Essa mudança troca otimização automática por controle explícito. O desempenho pode cair inicialmente para aplicações que dependiam do cache implícito, mas a experiência de depuração melhora drasticamente: o conteúdo cacheado está cacheado porque o código diz isso, não por causa de heurísticas do framework.
Cache em três níveis: arquivo, componente e função
A diretiva "use cache" opera em três níveis: arquivo, componente e função. Escolher o escopo correto é a decisão de cache mais importante no Next.js 16.
O cache em nível de arquivo marca cada export assíncrono em um arquivo como cacheável. É adequado para páginas com conteúdo completamente estático sem dados de usuário.
"use cache"
import { getPricingPlans } from "@/lib/data"
// Entire page is cached as a static shell
export default async function PricingPage() {
const plans = await getPricingPlans()
return (
<section>
{plans.map((plan) => (
<PricingCard key={plan.id} plan={plan} />
))}
</section>
)
}O cache em nível de componente cacheia componentes individuais dentro de uma página. Isso habilita o Partial Pre-Rendering: o componente cacheado é renderizado como parte do shell estático, enquanto componentes dinâmicos chegam via streaming.
async function ProductRecommendations({ categoryId }: { categoryId: string }) {
"use cache"
// categoryId becomes part of the automatic cache key
const products = await getTopProducts(categoryId)
return (
<ul>
{products.map((p) => (
<li key={p.id}>{p.name} - {p.price}</li>
))}
</ul>
)
}O cache em nível de função é aplicado diretamente a funções de busca de dados. Isso substitui o antigo padrão unstable_cache.
import { cacheLife } from "next/cache"
export async function getArticleBySlug(slug: string) {
"use cache"
cacheLife("hours")
// slug is automatically included in the cache key
const article = await db.article.findUnique({ where: { slug } })
return article
}O compilador gera automaticamente as chaves de cache a partir dos argumentos da função. Não é necessário usar arrays keyParts manuais nem workarounds com JSON.stringify. Os argumentos devem ser serializáveis (strings, números, objetos simples). Passar uma instância de classe ou uma função como argumento quebra a serialização.
Partial Pre-Rendering: shell estático com lacunas dinâmicas
Partial Pre-Rendering (PPR) era experimental no Next.js 14-15. No Next.js 16, PPR é estável e está integrado diretamente nos Cache Components através de cacheComponents: true no next.config.ts.
PPR permite que uma única rota seja parcialmente estática e parcialmente dinâmica ao mesmo tempo. O shell estático é servido instantaneamente a partir do CDN. O conteúdo dinâmico chega via streaming conforme as boundaries <Suspense> são resolvidas.
import { Suspense } from "react"
import { UserGreeting } from "@/components/UserGreeting"
import { StaticSidebar } from "@/components/StaticSidebar"
import { RecentActivity } from "@/components/RecentActivity"
export default function DashboardPage() {
return (
<div className="grid grid-cols-12 gap-6">
{/* Cached static shell - served instantly */}
<StaticSidebar />
<main className="col-span-9">
{/* Dynamic - streams in after static shell */}
<Suspense fallback={<GreetingSkeleton />}>
<UserGreeting />
</Suspense>
{/* Dynamic - streams independently */}
<Suspense fallback={<ActivitySkeleton />}>
<RecentActivity />
</Suspense>
</main>
</div>
)
}A árvore de decisão de renderização é direta: componentes com "use cache" fazem parte do shell estático. Componentes envolvidos em <Suspense> que leem cookies, headers ou outros dados específicos da requisição são transmitidos dinamicamente. Todo o resto é renderizado no momento da requisição.
O flag experimental.ppr e a configuração de segmento de rota experimental_ppr do Next.js 15 são removidos. O comportamento do PPR agora é controlado completamente por cacheComponents: true.
Adicionar cacheComponents: true no next.config.ts. Esse único flag habilita PPR, a diretiva "use cache" e o sistema completo de Cache Components. Nenhuma outra configuração é necessária.
Perfis cacheLife: substituindo revalidate
O export revalidate do Next.js 15 desaparece. Em seu lugar, cacheLife() fornece perfis nomeados que controlam a duração do cache. Os perfis integrados incluem seconds, minutes, hours, days, weeks e max.
import { cacheLife } from "next/cache"
export async function getExchangeRates() {
"use cache"
cacheLife("minutes") // Revalidates every few minutes
const rates = await fetch("https://api.exchangerate.host/latest")
return rates.json()
}
export async function getCompanyInfo() {
"use cache"
cacheLife("weeks") // Rarely changes
return db.company.findFirst()
}Perfis personalizados são definidos no next.config.ts:
import type { NextConfig } from "next"
const config: NextConfig = {
cacheComponents: true,
cacheLife: {
// Custom profile for product data
product: {
stale: 300, // Serve stale for 5 minutes
revalidate: 3600, // Revalidate in background every hour
expire: 86400, // Hard expire after 24 hours
},
},
}
export default configCentralizar os perfis na configuração significa que uma única alteração ajusta o cache em toda a aplicação. Isso elimina os valores revalidate: 3600 espalhados que eram problemáticos nas bases de código do Next.js 15.
Uma regra para lembrar: cacheLife() deve ser executado apenas uma vez por invocação de função. O cache condicional é válido apenas se uma única ramificação é executada:
export async function getProduct(id: string) {
"use cache"
const product = await db.product.findUnique({ where: { id } })
if (!product) {
// Short cache for missing items (may appear soon)
cacheLife("minutes")
return null
}
// Longer cache for existing products
cacheLife("product")
return product
}Pronto para mandar bem nas entrevistas de React / Next.js?
Pratique com nossos simuladores interativos, flashcards e testes tecnicos.
cacheTag para invalidação direcionada
Sem cacheTag(), uma função cacheada só pode expirar por tempo. A invalidação sob demanda requer etiquetar as entradas de cache e chamar revalidateTag() em uma Server Action.
import { cacheLife, cacheTag } from "next/cache"
export async function getProductById(id: string) {
"use cache"
cacheTag(`product-${id}`, "products")
cacheLife("days")
return db.product.findUnique({ where: { id } })
}"use server"
import { revalidateTag } from "next/cache"
export async function updateProduct(id: string, data: ProductUpdate) {
await db.product.update({ where: { id }, data })
// Invalidate this specific product AND the product list
revalidateTag(`product-${id}`)
revalidateTag("products")
}As tags suportam até 256 caracteres cada, com um máximo de 128 tags por entrada de cache. Uma convenção prática: usar tags em nível de entidade (product-123) para registros individuais e tags em nível de coleção (products) para páginas de listagem.
Uma função cacheada sem cacheTag() só pode expirar por tempo. A invalidação sob demanda é impossível. Isso é fácil de esquecer durante o desenvolvimento inicial e doloroso de descobrir quando um cliente reporta dados desatualizados em produção.
Segurança: use cache vs use cache private
A diretiva "use cache" por padrão cria um cache compartilhado. Qualquer combinação de argumentos produz uma entrada de cache que pode ser servida para qualquer usuário. Isso é correto para dados públicos mas perigoso para conteúdo personalizado.
"use cache: private" cria um cache por usuário que inclui a sessão atual na chave de cache. Pode acessar com segurança cookies() e headers() dentro do escopo cacheado.
// WRONG: User data in shared cache - data leak risk
export async function getUserDashboard(userId: string) {
"use cache"
return db.user.findUnique({
where: { id: userId },
include: { orders: true, preferences: true },
})
}
// CORRECT: Private cache scoped to the current user
export async function getUserDashboard() {
"use cache: private"
cacheLife("minutes")
const session = await cookies()
const userId = session.get("userId")?.value
return db.user.findUnique({
where: { id: userId },
include: { orders: true, preferences: true },
})
}A terceira variante, "use cache: remote", persiste o cache em armazenamento externo. Em ambientes serverless (Vercel, AWS Lambda), o cache em memória padrão é perdido durante cold starts. "use cache: remote" garante que as entradas de cache sobrevivam entre instâncias de função.
Uma matriz de decisão para entrevistas:
| Directive | Scope | Use When |
|-----------|-------|----------|
| "use cache" | Shared, all users | Public data: pricing, articles, product catalogs |
| "use cache: private" | Per-user session | Personalized data: dashboards, settings, order history |
| "use cache: remote" | Shared, external storage | High-traffic data in serverless environments |
Migração do Next.js 15 para Cache Components
A migração de unstable_cache para "use cache" é principalmente mecânica, mas tem três armadilhas que frequentemente aparecem em entrevistas.
Armadilha 1: Closures sobre dados com escopo de requisição. Se a função cacheada referencia um valor do escopo externo que varia por requisição (um header, um cookie, um ID de usuário), a conversão não é direta. É necessário passar esse valor como argumento explícito ou usar "use cache: private".
Armadilha 2: Cache condicional. Código que envolvia unstable_cache apenas quando uma condição era atendida precisa de reestruturação. "use cache" está sempre ativo uma vez aplicado. A condição deve ser movida para fora da função cacheada.
Armadilha 3: Chaves de cache manuais. unstable_cache exigia arrays keyParts explícitos. O compilador de "use cache" gera chaves automaticamente a partir dos argumentos mais um build ID e um hash da função. Remover o gerenciamento manual de chaves é o objetivo, mas é necessário verificar que todos os valores que diferenciam o cache sejam parâmetros reais da função.
Perguntas de entrevista: o que desenvolvedores seniores são perguntados
Estas perguntas refletem os padrões de entrevista reais em 2026 para posições Next.js seniores. Cada uma visa um aspecto específico dos Cache Components.
P1: Explicar a mudança do cache implícito para o explícito no Next.js 16. Por que o framework fez essa mudança?
O Next.js 14-15 cacheava chamadas fetch e páginas implicitamente. Depurar se uma página era estática ou dinâmica exigia rastrear múltiplas camadas de cache ocultas. O modelo explícito com "use cache" torna o cache visível no código-fonte. O trade-off: o desempenho pode cair inicialmente para aplicações migrando do cache implícito, mas os desenvolvedores ganham controle total e previsibilidade.
P2: Quais são os três escopos de "use cache" e quando cada um deve ser usado?
Nível de arquivo para páginas completamente estáticas. Nível de componente para misturar conteúdo cacheado e dinâmico dentro de uma página (o padrão PPR). Nível de função para cachear operações específicas de busca de dados. A escolha do escopo determina a granularidade do cache e os limites de invalidação.
P3: Uma equipe cacheia uma função que retorna o histórico de pedidos de um usuário com "use cache". O que acontece?
O cache compartilhado armazena o resultado indexado pelos argumentos da função. Se a função aceita um parâmetro userId, diferentes usuários obtêm diferentes entradas de cache, mas o cache continua sendo infraestrutura compartilhada. Se a função lê userId de cookies() em vez de parâmetros, o build falha porque cookies() é uma API de runtime proibida no escopo do cache compartilhado. A solução: mudar para "use cache: private" ou passar o user ID como argumento explícito.
P4: Como cacheLife difere do antigo export revalidate?
revalidate era um número único (segundos) definido no nível de página ou layout. cacheLife usa perfis nomeados com três dimensões: stale (servir conteúdo desatualizado), revalidate (intervalo de atualização em background) e expire (expiração forçada). Os perfis são centralizados no next.config.ts, então uma única alteração afeta todos os pontos de chamada que usam esse perfil.
P5: Descrever como PPR renderiza uma página de dashboard com uma sidebar estática e conteúdo dinâmico do usuário.
No build time, o Next.js gera um shell estático contendo a sidebar (marcada com "use cache") e fallbacks <Suspense> para as seções dinâmicas. Na requisição, o CDN serve o shell estático instantaneamente. O servidor então faz streaming do conteúdo dinâmico (saudação do usuário, feed de atividade) nas boundaries Suspense. O usuário vê o layout imediatamente e o conteúdo dinâmico é preenchido progressivamente.
P6: O que acontece com uma função cacheada sem cacheTag()?
Ela só pode expirar por tempo através do seu perfil cacheLife. A invalidação sob demanda via revalidateTag() é impossível. Este é um descuido comum que se manifesta quando editores de conteúdo atualizam um registro e esperam reflexo imediato no site. Toda função cacheada que possa precisar de invalidação sob demanda deve incluir pelo menos um cacheTag().
Para mais perguntas de entrevista sobre data fetching no Next.js, o SharpSkill oferece módulos de prática com sessões cronometradas e explicações detalhadas. O modulo de Server Actions no Next.js cobre os padrões de Server Actions que se associam ao revalidateTag.
Checklist prático para Cache Components em produção
- Habilitar
cacheComponents: truenonext.config.tse remover quaisquer flagsexperimental.pprouexperimental.dynamicIO - Auditar cada página: adicionar
"use cache"a páginas estáticas e funções de busca de dados que servem conteúdo público - Envolver todo o conteúdo dinâmico (específico do usuário, em tempo de requisição) em boundaries
<Suspense>com fallbacks skeleton significativos - Usar
"use cache: private"para qualquer função que acesse cookies, headers ou retorne dados personalizados - Definir perfis
cacheLifepersonalizados para categorias de dados comuns (dados de produto, sessões de usuário, conteúdo estático) - Adicionar
cacheTag()a cada função cacheada que possa requerer invalidação sob demanda - Testar em modo produção com
next build && next startporque o comportamento do cache emnext devdifere significativamente - Monitorar taxas de cache-hit por página durante 24 horas antes de implantar na próxima página
Comece a praticar!
Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.
Conclusão
- Next.js 16 substitui o cache implícito por
"use cache"explícito nos níveis de arquivo, componente e função - PPR é agora estável e padrão sob
cacheComponents: true, entregando shells estáticos com conteúdo dinâmico em streaming - Os perfis
cacheLifesubstituemrevalidatecom controle centralizado e tridimensional da duração do cache cacheTag+revalidateTaghabilitam a invalidação sob demanda; tags ausentes significam expiração apenas por tempo"use cache: private"é obrigatório para dados de usuário para prevenir vazamentos de dados entre usuários- As perguntas de entrevista em 2026 focam na mudança de implícito para explícito, no fluxo de renderização PPR, na segurança do cache e nas armadilhas de migração do Next.js 15
Comece a praticar!
Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.
Tags
Compartilhar
Artigos relacionados

React Compiler em 2026: memoização automática e perguntas de entrevista
Análise completa do React Compiler em 2026: pipeline de compilação, memoização automática, regras do React e perguntas frequentes em entrevistas técnicas.

React 19: Server Components em producao - O guia completo
Dominar os Server Components do React 19 em producao. Arquitetura, padroes, streaming, caching e otimizacoes para aplicacoes de alta performance.

React 19 useEffectEvent e Activity: novas APIs e perguntas de entrevista 2026
Analise aprofundada das APIs useEffectEvent e Activity do React 19.2. Solucoes para stale closures, pre-renderizacao em segundo plano, exemplos de codigo e perguntas de entrevista tecnica.