Performance é crucial para qualquer aplicação web moderna. Portanto, entender
estratégias de cache no Next.js pode transformar
completamente a experiência do usuário. Além disso, implementar cache
corretamente reduz custos de infraestrutura e melhora o SEO. Neste guia, você
vai aprender as principais estratégias de cache Next.js e
como aplicá-las na prática.
O Que É Cache no Next.js?
Cache é como uma “memória rápida” da sua aplicação. Em outras palavras, é uma
cópia temporária de dados armazenada para acesso instantâneo. Assim, quando um
usuário visita sua página, ela carrega muito mais rápido.
Imagine um restaurante que prepara alguns pratos populares antecipadamente.
Portanto, quando um cliente pede, o prato sai na hora. Consequentemente, o
atendimento fica mais rápido. Da mesma forma, o Next.js “prepara” páginas
antecipadamente para entregar rapidamente aos usuários.
O
Next.js oferece várias camadas de cache: geração estática, revalidação incremental e cache de dados. Além disso,
cada estratégia serve para cenários diferentes. Por exemplo, blogs usam
regeneração, enquanto landing pages usam geração estática pura.
Static Site Generation (SSG)
SSG gera páginas HTML no momento do build. Assim, o servidor entrega arquivos
prontos instantaneamente. Portanto, essa é a estratégia mais rápida possível.
Recomenda-se SSG quando o conteúdo muda pouco ou nada. Por exemplo, páginas
institucionais, documentação e landing pages. Dessa forma, você obtém
performance máxima com custo mínimo.
Veja a seguir a implementação básica:
// app/sobre/page.tsx
export default async function SobrePage() {
return (
<div>
<h1>Sobre Nós</h1>
<p>Conteúdo estático que raramente muda</p>
</div>
)
}
// Por padrão, componentes Server são SSG
// Página gerada uma vez no build
Além disso, com SSG você pré-renderiza rotas dinâmicas usando
generateStaticParams. Portanto, mesmo páginas dinâmicas ficam
estáticas:
// app/produto/[id]/page.tsx
export async function generateStaticParams() {
const produtos = await fetch('https://api.exemplo.com/produtos')
const data = await produtos.json()
return data.map((produto) => ({
id: produto.id.toString()
}))
}
export default async function ProdutoPage({ params }) {
const produto = await fetch(`https://api.exemplo.com/produtos/${params.id}`)
const data = await produto.json()
return <div>{data.nome}</div>
}
// Gera /produto/1, /produto/2, etc. no build
Incremental Static Regeneration (ISR)
ISR combina o melhor dos dois mundos: velocidade do estático com atualização do dinâmico. Em outras palavras,
páginas são geradas estaticamente, mas regeneram automaticamente após um
período.
Pense em um jornal digital que imprime edições a cada hora. Assim, leitores
sempre veem conteúdo recente, mas não esperam pela geração. Consequentemente,
você tem performance com dados atualizados.
Essa estratégia funciona bem para blogs, e-commerce e dashboards com dados que
mudam periodicamente. Por exemplo, artigos de blog podem regenerar a cada
hora. Dessa forma, novos posts aparecem sem rebuild completo.
Veja a seguir a implementação com revalidação temporal:
// app/blog/page.tsx
export const revalidate = 3600 // 1 hora em segundos
export default async function BlogPage() {
const posts = await fetch('https://api.exemplo.com/posts')
const data = await posts.json()
return (
<div>
{data.map(post => (
<article key={post.id}>
<h2>{post.titulo}</h2>
</article>
))}
</div>
)
}
// Página regenera automaticamente após 1 hora
// Primeira requisição após 1h serve cache antigo
// Segunda requisição já vê a versão atualizada
O ISR funciona em dois tempos. Primeiro, serve a página em cache. Depois,
regenera em background. Portanto, usuários nunca esperam pela regeneração.
Além disso, você controla a frequência de atualização com a
configuração revalidate.
On-Demand Revalidation
Revalidação sob demanda invalida o cache quando você quiser. Por exemplo,
quando publica um novo post ou atualiza um produto. Dessa forma, o cache
atualiza imediatamente, não após um tempo.
Imagine uma loja que repõe prateleiras assim que recebe mercadoria nova.
Consequentemente, clientes sempre veem os produtos mais recentes. Similarmente,
revalidação sob demanda atualiza o cache instantaneamente.
A seguir, veja como criar uma API Route para revalidação:
// app/api/revalidate/route.ts
import { revalidatePath, revalidateTag } from 'next/cache'
import { NextRequest, NextResponse } from 'next/server'
export async function POST(request: NextRequest) {
const body = await request.json()
const { secret, path, tag } = body
// Validar token de segurança
if (secret !== process.env.REVALIDATE_SECRET) {
return NextResponse.json({ error: 'Token inválido' }, { status: 401 })
}
try {
// Revalidar caminho específico
if (path) {
revalidatePath(path)
return NextResponse.json({ revalidated: true, path })
}
// Ou revalidar por tag
if (tag) {
revalidateTag(tag)
return NextResponse.json({ revalidated: true, tag })
}
return NextResponse.json({ error: 'Path ou tag necessário' }, { status: 400 })
} catch (error) {
return NextResponse.json({ error: 'Erro ao revalidar' }, { status: 500 })
}
}
Em seguida, veja como chamar a API de revalidação:
// Chamada manual para revalidar
fetch('https://seusite.com/api/revalidate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: process.env.REVALIDATE_SECRET,
path: '/blog'
})
})
// Ou revalidar por tag
fetch('https://seusite.com/api/revalidate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: process.env.REVALIDATE_SECRET,
tag: 'posts'
})
})
// Útil em webhooks de CMS headless, actions do GitHub,
// ou qualquer automação que detecte mudanças de conteúdo
Aplique revalidação sob demanda com CMS headless, e-commerce e painéis admin.
Portanto, quando atualizar dados no backend, o cache atualiza instantaneamente
no frontend. Além disso, você combina performance de cache com dados sempre
atualizados. A
função revalidatePath
e
revalidateTag
facilitam essa implementação.
Cache de Dados com Fetch
Next.js estende o fetch nativo com cache automático. Dessa forma,
você controla como cada requisição é cacheada. Consequentemente, otimiza cada
chamada de API individualmente.
A
documentação oficial do Next.js
explica detalhadamente as opções de cache. Portanto, consulte para casos
avançados.
Abaixo estão as principais opções de cache no fetch:
// Cache padrão - armazena indefinidamente
const dados1 = await fetch('https://api.exemplo.com/dados', {
cache: 'force-cache' // Padrão no Next.js 14+
})
// Sem cache - sempre busca dados frescos
const dados2 = await fetch('https://api.exemplo.com/dados', {
cache: 'no-store' // Útil para dados em tempo real
})
// Cache com revalidação temporal
const dados3 = await fetch('https://api.exemplo.com/dados', {
next: { revalidate: 60 } // Revalida a cada 60 segundos
})
// Cache com tags para revalidação seletiva
const dados4 = await fetch('https://api.exemplo.com/posts', {
next: { tags: ['posts'] }
})
// Depois, invalida apenas esse cache:
// revalidateTag('posts')
Finalmente, veja um exemplo prático combinando estratégias:
// app/dashboard/page.tsx
export const revalidate = 300 // 5 minutos
export default async function DashboardPage() {
// Dados de usuário - sempre frescos
const usuario = await fetch('https://api.exemplo.com/usuario', {
cache: 'no-store'
})
// Estatísticas - cache de 5 minutos
const stats = await fetch('https://api.exemplo.com/stats', {
next: { revalidate: 300 }
})
// Configurações - cache permanente
const config = await fetch('https://api.exemplo.com/config', {
cache: 'force-cache'
})
const [usuarioData, statsData, configData] = await Promise.all([
usuario.json(),
stats.json(),
config.json()
])
return (
<div>
<h1>Olá, {usuarioData.nome}</h1>
<p>Vendas hoje: {statsData.vendas}</p>
</div>
)
}
Escolhendo a Estratégia Certa
Cada projeto tem necessidades diferentes. Portanto, escolha a estratégia
baseado em frequência de atualização e criticidade dos dados.
SSG é ideal quando:
- Conteúdo raramente muda (institucional, documentação)
- Performance é prioridade máxima
- Você quer custos mínimos de servidor
Por outro lado, escolha ISR quando:
- Conteúdo atualiza periodicamente (blogs, notícias)
- Você quer balance entre performance e atualização
- Tem muitas páginas dinâmicas
Já a revalidação sob demanda funciona melhor quando:
- Usa CMS headless ou sistema de gestão de conteúdo
- Precisa atualizar cache imediatamente após mudanças
- Quer controle total sobre invalidação de cache
Finalmente, no-store é necessário quando:
- Dados mudam constantemente (tempo real)
- Informações personalizadas por usuário
- Dados sensíveis que não devem ser cacheados
Na prática, você provavelmente vai combinar estratégias. Por exemplo, ISR na
listagem de posts com revalidação sob demanda. Assim, otimiza performance
enquanto mantém conteúdo atualizado.
Conclusão
Dominar estratégias de cache no Next.js é essencial para criar aplicações
rápidas e eficientes. Portanto, comece identificando quais páginas mudam com
frequência. Em seguida, aplique a estratégia adequada para cada caso.
Lembre-se: cache bem implementado melhora performance, reduz custos e aumenta
satisfação do usuário. Além disso, o Next.js facilita com APIs simples e
intuitivas. Consequentemente, você implementa cache avançado com poucas linhas
de código.
Primeiro, comece testando ISR em uma página de blog. Assim, você experimenta
os benefícios sem complexidade. Em seguida, adicione revalidação sob demanda
para controle total. Por fim, otimize cada requisição com as opções de
fetch.
Quer aprender mais sobre React e boas práticas? Confira nosso guia sobre
princípios SOLID aplicados ao React e
descubra como escrever código mais limpo e sustentável em suas aplicações Next.js.
- Titânio Aeroespacial e resistência
- Até 100m de resistencia a água do mar
- Bateria de até 100h