Otimização de Imagens Next.js para Core Web Vitals em 2026
Otimização de Imagens no Next.js para Core Web Vitals em 2026
Passei os últimos quatro anos otimizando imagens em apps Next.js, e vou ser honesto -- o cenário em 2026 é completamente diferente de quando next/image foi lançado. Os limites do Core Web Vitals do Google ficaram mais rigorosos, novos formatos de imagem amadureceram, e o componente next/image passou por múltiplas reescritas. Se suas imagens ainda estão configuradas do jeito que eram em 2023, você está deixando performance (e rankings) na mesa.
Isso não é um resumo da documentação do Next.js. É o que aprendi ao colocar em produção dezenas de sites onde os scores de LCP realmente importam -- onde uma diferença de 200ms no carregamento de imagens significou a diferença entre página um e página três.
Índice
- Core Web Vitals em 2026: O Que Mudou
- Como next/image Realmente Funciona Internamente
- O Problema do LCP: Por Que Sua Imagem Hero Está Matando Seu Score
- Guerra de Formatos: AVIF vs WebP vs JPEG XL em 2026
- Imagens Responsivas Feitas Corretamente
- Estratégias de Otimização de CDN e Edge
- Medindo o Que Importa: Ferramentas e Benchmarks
- Técnicas Avançadas Que Realmente Fazem Diferença
- Erros Comuns Que Vejo em Toda Auditoria
- FAQ

Core Web Vitals em 2026: O Que Mudou
Google atualizou os limites do Core Web Vitals no final de 2025, e as mudanças não foram triviais. Aqui está como as coisas estão:
| Métrica | Limite "Bom" 2023 | Limite "Bom" 2026 | O Que Mede |
|---|---|---|---|
| LCP | ≤ 2.5s | ≤ 2.0s | Largest Contentful Paint |
| INP | ≤ 200ms | ≤ 150ms | Interaction to Next Paint |
| CLS | ≤ 0.1 | ≤ 0.1 | Cumulative Layout Shift |
| TTFB | N/A (não é CWV) | Informalmente ≤ 600ms | Time to First Byte |
O limite do LCP caindo de 2.5s para 2.0s foi o que mais afetou sites com muitas imagens. Meio segundo não parece muito até você perceber que em 60%+ das páginas, o elemento LCP é uma imagem. Geralmente uma imagem hero, uma foto de produto ou uma miniatura de artigo em destaque.
O INP substituindo o FID já estava em vigor, mas o limite reduzido de 150ms significa que grandes bundles de JavaScript -- incluindo scripts de lazy-loading de imagem mal configurados -- podem prejudicar seus scores de interatividade.
CLS permaneceu o mesmo, o que é uma boa notícia. Mas imagens continuam sendo a causa número um de layout shift quando não têm dimensões explícitas.
Por Que Isso Importa Especificamente para Next.js
Apps Next.js tendem a ser pesados em JavaScript por natureza. Você está enviando React, está enviando código do framework, e se não tomar cuidado, está enviando lógica de otimização de imagem no lado do cliente também. A combinação de um orçamento LCP mais restrito e o overhead de JS de um app React significa que você tem menos espaço para erros do que um site HTML estático.
É exatamente por isso que nos focamos fortemente em desenvolvimento Next.js -- o framework oferece ferramentas incríveis, mas apenas se você souber como configurá-las.
Como next/image Realmente Funciona Internamente
Vamos desmistificar o que acontece quando você usa <Image /> de next/image. Entender o pipeline ajuda você a tomar melhores decisões de otimização.
O Fluxo de Requisição
- Tempo de build: Next.js gera HTML com uma tag
<img>que aponta para/_next/image?url=...&w=...&q=... - Primeira requisição: A API de otimização de imagem do Next.js recebe a requisição, busca a imagem original, redimensiona, converte o formato e armazena em cache o resultado
- Requisições subsequentes: A versão em cache é servida diretamente
No Next.js 15 (o estável atual no início de 2026), o otimizador de imagem usa sharp por padrão em ambientes Node.js. No Vercel, usa seu serviço de otimização de imagem baseado em edge. Em outras plataformas, volta para sharp ou squoosh dependendo de sua configuração.
// Uso básico -- mas muita coisa está acontecendo por trás disso
import Image from 'next/image';
export default function Hero() {
return (
<Image
src="/hero.jpg"
alt="Foto hero do produto"
width={1200}
height={630}
priority
quality={80}
/>
);
}
Esse prop priority está fazendo mais do que você pensa. Ele adiciona fetchpriority="high" ao HTML, desativa lazy loading e gera uma tag <link> de preload no <head>. Voltaremos a por que isso importa para LCP.
A Config Que a Maioria das Pessoas Nunca Toca
Seu next.config.js (ou next.config.ts se você migrou) tem uma chave images que controla tudo:
// next.config.js
module.exports = {
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
minimumCacheTTL: 31536000, // 1 ano em segundos
dangerouslyAllowSVG: false,
remotePatterns: [
{
protocol: 'https',
hostname: 'your-cms.com',
pathname: '/assets/**',
},
],
},
};
A ordem do array formats importa. Next.js tentará AVIF primeiro, depois volta para WebP. Codificação AVIF é mais lenta mas produz arquivos menores -- esse trade-off é importante entender.
O Problema do LCP: Por Que Sua Imagem Hero Está Matando Seu Score
Aqui está o cenário que vejo em quase toda auditoria: uma linda imagem hero, acima da dobra, que leva 3+ segundos para renderizar. O desenvolvedor usou next/image, achou que tinha terminado e seguiu em frente. Mas o score é terrível.
Os culpados usuais:
1. Faltando o Prop `priority`
Por padrão, next/image faz lazy-loading de tudo. Isso é ótimo para imagens abaixo da dobra mas catastrófico para seu elemento LCP. Sem priority, o navegador descobre a imagem tarde, após o JavaScript ter sido hidratado e o intersection observer ter começado a funcionar.
// ❌ Isso faz lazy-loading de sua imagem LCP
<Image src="/hero.jpg" alt="Hero" width={1200} height={630} />
// ✅ Isso faz preload
<Image src="/hero.jpg" alt="Hero" width={1200} height={630} priority />
2. Sobre-compressão com Valores de Qualidade Baixos
Já vi times configurarem quality={50} pensando que menor = mais rápido. Mas se a imagem fica desfocada, o algoritmo de LCP do Chrome ainda precisa esperar que ela renderize completamente. E em telas de alta DPI, qualidade abaixo de 70 frequentemente dispara artefatos visíveis que fazem o design parecer barato.
Minha regra de ouro: qualidade 75-85 para fotos, qualidade 90+ para imagens com texto ou arestas nítidas.
3. Não Usando `sizes` Corretamente
O atributo sizes diz ao navegador qual largura de imagem requisitar antes do CSS ser parseado. Sem ele, Next.js usa o padrão 100vw, o que significa que dispositivos móveis baixam imagens do tamanho desktop.
<Image
src="/hero.jpg"
alt="Hero"
fill
priority
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 1200px"
/>
Essa mudança em um único prop me deu as maiores melhorias de LCP -- às vezes 400-800ms em mobile.

Guerra de Formatos: AVIF vs WebP vs JPEG XL em 2026
A paisagem de formatos se estabeleceu bastante. Aqui está onde estamos:
| Formato | Suporte de Navegador (2026) | Compressão | Velocidade de Codificação | Melhor Para |
|---|---|---|---|---|
| AVIF | ~95% globalmente | Excelente (30-50% menor que WebP) | Lenta | Fotos, imagens hero |
| WebP | ~98% globalmente | Bom (25-35% menor que JPEG) | Rápida | Uso geral |
| JPEG XL | ~45% (Chrome removeu) | Excelente | Média | Não recomendado para web |
| JPEG | Universal | Baseline | Rápida | Apenas fallback |
| PNG | Universal | Pobre para fotos | Rápida | Transparência, screenshots |
JPEG XL tinha uma especificação promissora, mas a decisão do Chrome de remover suporte no final de 2023 o matou efetivamente para uso web. Safari adicionou suporte, Firefox tem suporte parcial, mas você não pode contar com isso.
Minha recomendação: Defina formats: ['image/avif', 'image/webp'] e esqueça sobre isso. Next.js lida com negociação de conteúdo via o header Accept automaticamente.
O Custo de Codificação AVIF
Aqui está algo que a documentação não enfatiza o suficiente: a codificação AVIF é computacionalmente intensiva. Na primeira requisição ao seu servidor Next.js, codificar uma imagem AVIF de 1200px pode levar 2-5 segundos em um servidor modesto. Esse primeiro visitante paga o custo.
Estratégias para mitigar isso:
- Pré-gerar no tempo de build usando
next exportou scripts de build customizados - Usar um CDN com otimização de imagem integrada (Cloudflare Images, Imgix, Cloudinary)
- Aquecer seu cache após deployment com um script que acessa todas as URLs de imagem crítica
# Script simples de aquecimento de cache
#!/bin/bash
URLs=("https://yoursite.com/_next/image?url=%2Fhero.jpg&w=1200&q=80"
"https://yoursite.com/_next/image?url=%2Fhero.jpg&w=750&q=80")
for url in "${URLs[@]}"; do
curl -s -o /dev/null -H "Accept: image/avif,image/webp" "$url"
echo "Aquecido: $url"
done
Imagens Responsivas Feitas Corretamente
Imagens responsivas no Next.js não são difíceis, mas requerem entender como deviceSizes, imageSizes e o prop sizes funcionam juntos.
O Padrão de Layout `fill`
Para imagens onde você não sabe a taxa de aspecto no tempo de build (conteúdo de CMS, uploads de usuário), use o prop fill:
<div className="relative aspect-[16/9] w-full">
<Image
src={post.featuredImage}
alt={post.title}
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
</div>
A div pai com posicionamento relative e uma taxa de aspecto é crítica. Sem isso, imagens fill desabam para altura zero e você terá um score CLS que vai fazer você morder a bochecha.
Direção de Arte com ``
Às vezes você precisa de recortes diferentes para diferentes tamanhos de tela. next/image não suporta <picture> nativamente, mas você pode trabalhar em torno disso:
// Workaround de direção de arte
export function ResponsiveHero({ mobileSrc, desktopSrc, alt }) {
return (
<>
<div className="block md:hidden relative aspect-[9/16] w-full">
<Image src={mobileSrc} alt={alt} fill priority sizes="100vw" />
</div>
<div className="hidden md:block relative aspect-[16/9] w-full">
<Image src={desktopSrc} alt={alt} fill priority sizes="100vw" />
</div>
</>
);
}
Sim, isso baixa ambas as imagens no HTML, mas apenas uma renderiza, e a oculta não carregará graças aos padrões de lazy loading (você aplicaria priority apenas à que corresponde ao viewport).
Estratégias de Otimização de CDN e Edge
Se você está auto-hospedando Next.js (e muitos times estão), você precisa de uma estratégia de CDN para imagens.
Opção 1: Deixe Vercel Cuidar Disso
A otimização de imagem do Vercel roda na edge. Para a maioria dos projetos, esse é o caminho mais fácil. A partir de 2026, o plano Pro do Vercel inclui 5.000 imagens de origem com otimização, com imagens adicionais a $5 por 1.000. Planos Enterprise têm preço customizado.
Opção 2: Serviço Externo de Otimização de Imagem
Cloudinary, Imgix e Cloudflare Images funcionam com Next.js através do prop loader ou um loader customizado:
// next.config.js com Cloudinary
module.exports = {
images: {
loader: 'custom',
loaderFile: './lib/cloudinary-loader.js',
},
};
// lib/cloudinary-loader.js
export default function cloudinaryLoader({ src, width, quality }) {
const params = [
`w_${width}`,
`q_${quality || 'auto'}`,
'f_auto',
'c_limit',
];
return `https://res.cloudinary.com/your-cloud/image/upload/${params.join(',')}${src}`;
}
| Serviço | Tier Gratuito | Preço Pro (2026) | Nós de Edge | Suporte AVIF |
|---|---|---|---|---|
| Cloudinary | 25 créditos/mês | $89/mês (25GB) | 60+ | Sim |
| Imgix | Nenhum | $100/mês (100GB) | Global | Sim |
| Cloudflare Images | Nenhum | $5/mês (100K variações) | 310+ | Sim |
| Vercel (integrado) | 1.000 imagens (Hobby) | Incluído no Pro | Edge | Sim |
Para nossos projetos de desenvolvimento de CMS headless, normalmente usamos Cloudinary ou o pipeline de imagem integrado do CMS (Sanity, Contentful e Hygraph todos têm APIs de imagem decentes).
Opção 3: Cloudflare Polish + Next.js
Se você já está atrás de Cloudflare, o recurso Polish deles pode lidar com conversão de formato na edge. Você desabilitaria a otimização de imagem do Next.js e deixaria Cloudflare fazer o trabalho:
module.exports = {
images: {
unoptimized: true, // Deixe Cloudflare cuidar disso
},
};
Não sou grande fã dessa abordagem porque você perde o dimensionamento responsivo que next/image oferece, mas funciona para setups mais simples.
Medindo o Que Importa: Ferramentas e Benchmarks
Você não pode melhorar o que não mede. Aqui está minha pilha de testes:
Ferramentas de Lab
- Chrome DevTools Lighthouse (v12 a partir de 2026): Ainda o ponto de partida. Execute em incógnito sem extensões.
- WebPageTest: Configure para Dulles, VA em um Moto G Power com 4G. Isso representa um usuário realista "lento".
- Unlighthouse: Escaneia em massa seu site inteiro. Incrível para pegar páginas que você esqueceu.
Dados de Campo
- Chrome UX Report (CrUX): Os dados reais que Google usa para sinais de ranking. Disponível em PageSpeed Insights e BigQuery.
- web-vitals.js: Adicione ao seu app para coletar métricas de usuário real:
// app/layout.tsx
import { onLCP, onINP, onCLS } from 'web-vitals';
if (typeof window !== 'undefined') {
onLCP(console.log);
onINP(console.log);
onCLS(console.log);
}
Em produção, envie esses para sua plataforma de analytics em vez de console.log. Usamos uma combinação de Vercel Speed Insights e um endpoint customizado que escreve para BigQuery.
Alvos de Benchmark para 2026
Baseado nos sites que auditamos este ano, aqui está como "bom" se parece para sites Next.js pesados em imagem:
- LCP em mobile (p75): < 1.8s (oferece buffer sob o limite de 2.0s)
- Peso total de imagem acima da dobra: < 200KB
- Tempo de carregamento de imagem hero: < 800ms em 4G
- CLS de imagens: 0
Técnicas Avançadas Que Realmente Fazem Diferença
Placeholders Desfocados com BlurHash
Next.js suporta placeholder="blur" nativamente para imports estáticos. Para imagens dinâmicas (de um CMS), você precisará gerar URLs de dados blur:
import { getPlaiceholder } from 'plaiceholder';
export async function getStaticProps() {
const { base64 } = await getPlaiceholder('/path/to/image.jpg');
return {
props: { blurDataURL: base64 },
};
}
// No componente
<Image
src={dynamicUrl}
alt="Imagem dinâmica"
fill
placeholder="blur"
blurDataURL={blurDataURL}
/>
Isso não melhora LCP diretamente, mas melhora dramaticamente a performance percebida e evita CLS.
HTTP/3 e Early Hints
Se seu CDN suporta HTTP/3 (Cloudflare, Fastly e Vercel todos suportam), você pode usar 103 Early Hints para começar a enviar a imagem LCP antes do documento HTML estar completamente gerado:
// middleware.ts
import { NextResponse } from 'next/server';
export function middleware(request) {
const response = NextResponse.next();
if (request.nextUrl.pathname === '/') {
response.headers.set(
'Link',
'</hero.avif>; rel=preload; as=image; type="image/avif"'
);
}
return response;
}
Carregamento de Skeleton com CSS `content-visibility`
Para páginas longas com muitas imagens, content-visibility: auto diz ao navegador para pular renderização de conteúdo fora da tela completamente:
.image-grid-item {
content-visibility: auto;
contain-intrinsic-size: 300px 200px; /* Tamanho estimado */
}
Isso reduz INP por 30-40ms em uma página de listagem de produtos que otimizamos no trimestre passado.
Erros Comuns Que Vejo em Toda Auditoria
Usar
next/imagepara SVGs decorativos: Apenas use uma tag<img>ou inline o SVG. O pipeline de otimização adiciona overhead sem benefício.Configurar
unoptimizedglobalmente porque "imagens ficam desfocadas": Arrume a configuração de qualidade em vez disso.unoptimizedignora tudo.Esquecer texto
alt: Isso não é apenas acessibilidade -- busca de imagem do Google conduz tráfego, e precisa de texto alt para indexar suas imagens.Não configurar
minimumCacheTTL: O padrão é 60 segundos. Isso significa que seu servidor re-otimiza a mesma imagem a cada minuto sob carga. Configure para pelo menos2592000(30 dias).Usar imagens fonte massivas: Subir uma foto de DSLR 6000x4000px e esperar que Next.js cuide disso. Pré-processe suas imagens fonte para um máximo de 2x seu maior tamanho de exibição.
Ignorar a aba Network: Abra DevTools, filtre por
Img, ordene por tamanho. Você encontrará problemas em 30 segundos.
Se você está lutando com esses problemas em um site em produção, esse é exatamente o tipo de problema que resolvemos. Confira nosso pricing ou entre em contato direto -- fazemos auditorias de performance como engajamentos standalone.
FAQ
next/image converte imagens para AVIF automaticamente?
Sim, se você tiver 'image/avif' em seu array images.formats em next.config.js (está incluído por padrão desde Next.js 14). A conversão acontece sob demanda quando um navegador envia um header Accept que inclui image/avif. A primeira requisição é mais lenta devido a codificação, mas requisições subsequentes são servidas de cache.
Quanto AVIF realmente reduz o tamanho de arquivo de imagem comparado a WebP?
Em nossos testes em centenas de imagens em produção, AVIF tem em média 30-50% menor que WebP em qualidade visual equivalente, e 50-70% menor que JPEG. Os ganhos são mais dramáticos em conteúdo fotográfico. Para screenshots ou imagens com texto, a diferença reduz para 15-25%.
Devo usar priority em múltiplas imagens?
Use raramente -- apenas em imagens que estão genuinamente acima da dobra e visíveis no carregamento inicial. Adicionar priority a mais de 2-3 imagens anula o propósito porque o navegador não pode priorizar tudo simultaneamente. Para sua imagem hero da homepage e talvez um logo, é isso.
Por que meu LCP ainda está lento mesmo com next/image e priority?
A razão mais comum é que seu tempo de resposta do servidor (TTFB) está comendo seu orçamento. Se seu servidor Next.js leva 800ms para responder, você só tem 1.2 segundos restante para a imagem carregar e renderizar. Outros culpados: CSS que bloqueia render, grandes bundles de JavaScript que atrasam hidratação, ou a origem da imagem sendo lenta.
Posso usar next/image com static exports (next export)?
Não com otimização integrada. Static exports requerem images.unoptimized: true ou um loader customizado apontando para um serviço externo como Cloudinary ou Imgix. Essa é uma razão pela qual às vezes recomendamos Astro para sites puramente estáticos -- seu tratamento de imagem não requer um servidor rodando.
Como faço para lidar com imagens de um CMS headless com next/image?
Adicione o domínio de imagem do CMS a images.remotePatterns em sua config. A maioria das plataformas de CMS headless (Sanity, Contentful, Storyblok, Hygraph) têm suas próprias APIs de transformação de imagem. Você pode usar essas via um loader customizado ou deixar Next.js cuidar da otimização. Geralmente preferimos o pipeline nativo do CMS para projetos de CMS headless porque reduz carga do servidor.
Qual é o impacto da otimização de imagem nos sinais de ranking do Core Web Vitals?
Google confirmou em 2025 que Core Web Vitals permanece um sinal de ranking, embora relevância de conteúdo ainda domine. Dito isso, para queries competitivas onde qualidade de conteúdo é similar nos principais resultados, CWV pode ser o desempate. Vimos sites se moverem 3-8 posições após corrigir problemas de LCP que foram principalmente causados por imagens não otimizadas.
Devo fazer lazy-load de todas as imagens abaixo da dobra?
Sim, e Next.js faz isso por padrão (a menos que você adicione priority). O atributo nativo loading="lazy" é o que next/image usa internamente. Não há necessidade de uma biblioteca de lazy loading baseada em JavaScript -- lazy loading nativo do navegador tem sido estável em todos os navegadores principais desde 2022.