Otimização de imagens no Next.js: guia completo do componente Image

Pontuação no Lighthouse: 62.
Depois de duas semanas trabalhando em um projeto Next.js, descobri que a pontuação de desempenho mal chegava ao mínimo aceitável. Ao abrir a seção Performance, o maior problema estava bem na minha frente: LCP (Largest Contentful Paint) de 4,8 segundos, provocado pelas imagens.
Na hora, fiquei sem entender. Eu já estava usando Next.js; o framework não deveria otimizar isso automaticamente? Ao olhar o código, vi que a enorme imagem Hero da página inicial ainda usava a tag <img> mais básica possível. Na listagem da loja, dezenas de fotos de produtos vinham diretamente do servidor no tamanho original, com 3 a 4 MB cada.
Foi aí que entendi: embora o Next.js seja poderoso, você precisa usar ativamente o componente Image para aproveitar a otimização de imagens. Quando ele é usado corretamente, o tamanho dos arquivos pode cair de 60% a 80%, e o LCP pode passar de mais de 4 segundos para menos de 2.
O problema é que muita gente, assim como eu, ainda tropeça mesmo depois de adotar o componente Image. Imagens remotas geram o erro “Un-configured Host”, a página salta enquanto elas carregam e há tantas opções de configuração que fica difícil saber por onde começar. Neste artigo, reuni os problemas que enfrentei e as respectivas soluções para mostrar, do zero, como usar corretamente o componente Image do Next.js.
Por que usar o componente Image do Next.js?
Três problemas da tag img comum
Você pode pensar que exibir uma imagem se resume a escrever <img src="xxx">. Eu também pensava assim, até rodar um teste de desempenho e perceber o tamanho do problema.
Primeiro problema: nenhum formato é otimizado e a largura de banda é desperdiçada
Com uma tag img comum, o navegador exibe exatamente o formato fornecido. Se você enviou um PNG de 3 MB, o usuário baixa 3 MB. Hoje, quase todos os navegadores aceitam WebP, que pode ser 30% menor que JPEG, enquanto os que aceitam AVIF podem economizar mais 40%. A tag img, porém, não cuida disso: ela simplesmente carrega o arquivo indicado.
Segundo problema: a mesma imagem é usada em qualquer tamanho de tela
Isso fica muito evidente no celular. Você publica uma imagem de alta resolução com 2000 x 1500 pixels, mas a tela do usuário tem apenas 375 pixels de largura. Mesmo assim, o aparelho baixa o arquivo completo para o navegador reduzi-lo na exibição. O tráfego é desperdiçado e o carregamento fica mais lento.
Terceiro problema: mudanças de layout deixam a página irritante
Você provavelmente já passou por isso: abre uma página, está prestes a tocar em um botão e, de repente, uma imagem aparece, desloca todo o conteúdo para baixo e faz você tocar no lugar errado. Esse é o CLS (Cumulative Layout Shift). O Google o considera uma das métricas centrais dos Core Web Vitals, e ele afeta diretamente o SEO.
O que o componente Image otimiza automaticamente
O componente Image do Next.js existe justamente para resolver esses problemas. Ele não é apenas um invólucro para a tag img, mas uma solução completa de otimização de imagens.
Seleção automática de formato
O componente Image verifica o cabeçalho Accept enviado pelo navegador para descobrir quais formatos ele aceita. Se houver suporte a AVIF, entrega AVIF; caso contrário, usa WebP quando disponível e só mantém o formato original se nenhum dos dois for aceito. Tudo isso acontece automaticamente, sem uma linha extra de código.
Em um teste que fiz, um JPEG de 500 KB caiu para 180 KB em WebP e apenas 120 KB em AVIF. Imagine a economia de largura de banda quando um site contém dezenas ou centenas de imagens.
Carregamento responsivo
O componente Image gera e carrega automaticamente uma imagem adequada ao tamanho da tela. Um celular recebe a versão de 375 pixels de largura, enquanto um desktop recebe a de 1920 pixels. Esse recurso se chama srcset. Também é possível implementá-lo com uma tag img, mas você teria de escrever várias configurações manualmente; o componente Image cuida disso.
Lazy loading
Por padrão, o componente Image carrega apenas as imagens que entram no viewport. As imagens no fim da página só começam a ser baixadas quando o usuário rola até elas. Isso reduz bastante o volume de dados do primeiro carregamento e faz a página abrir mais rápido.
Nos meus testes em um projeto real, usar corretamente o componente Image do Next.js reduziu o tamanho das imagens em 60% a 80%, manteve o LCP abaixo de 2,5 segundos e deixou o CLS próximo de zero. Não são apenas números teóricos.
Uso básico: imagens locais e imagens remotas
Quando começamos a usar o componente Image, uma dúvida é comum: por que algumas imagens funcionam imediatamente e outras geram erro? A principal diferença está no tratamento de imagens locais e remotas.
Imagens locais: o caso mais simples
Imagens locais são arquivos incluídos no próprio projeto. Há duas maneiras comuns de usá-las.
Opção 1: importar o arquivo (recomendado)
import heroImage from '/public/images/hero.jpg'
import Image from 'next/image'
export default function Home() {
return (
<Image
src={heroImage}
alt="Hero image"
/>
)
}
Essa é a forma mais prática. Durante o build, o Next.js lê automaticamente a largura e a altura da imagem, então você nem precisa informar width e height. Hoje, é assim que trato a maioria das imagens locais.
Opção 2: informar o caminho diretamente
<Image
src="/images/hero.jpg"
width={1920}
height={1080}
alt="Hero image"
/>
Se a imagem estiver na pasta public, também é possível informar o caminho diretamente. Nesse caso, porém, você precisa definir a largura e a altura manualmente; se esquecer, ocorrerá um erro.
Imagens remotas: onde mais surgem problemas
Imagens remotas vêm de uma URL externa, como um serviço de armazenamento em nuvem. Esse é o caso que mais costuma causar dificuldades.
Erro comum: “Un-configured Host”
<Image
src="https://images.unsplash.com/photo-123456"
width={800}
height={600}
alt="Sample image"
/>
Se você usar o componente assim, provavelmente verá este erro:
Error: Invalid src prop (https://images.unsplash.com/photo-123456) on `next/image`,
hostname "images.unsplash.com" is not configured under images in your `next.config.js`
Por que isso acontece? O Next.js impede que usuários mal-intencionados aproveitem seu servidor para otimizar imagens de qualquer URL e consumam seus recursos. Por isso, exige uma declaração explícita dos domínios cujas imagens podem ser otimizadas.
Solução correta: configurar remotePatterns
Adicione esta configuração ao next.config.js, recomendada a partir do Next.js 14:
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.unsplash.com',
port: '',
pathname: '/**',
},
{
protocol: 'https',
hostname: 's3.amazonaws.com',
port: '',
pathname: '/my-bucket/**',
},
],
},
}
module.exports = nextConfig
O significado de cada opção é este:
protocol: https ou http; normalmente, use httpshostname: domínio da imagem, que deve corresponder exatamenteport: número da porta; em geral, fica vaziopathname: padrão do caminho;/**aceita todos os caminhos, mas você também pode limitá-lo
Depois de alterar a configuração, reinicie o servidor de desenvolvimento. Mudanças em arquivos de configuração só entram em vigor após a reinicialização. Na primeira vez, esqueci dessa etapa, achei que a configuração não funcionava e perdi meia hora investigando.
Configuração antiga (não recomendada)
Alguns tutoriais ainda mostram a opção domains:
module.exports = {
images: {
domains: ['images.unsplash.com', 's3.amazonaws.com'],
},
}
Essa sintaxe foi descontinuada a partir do Next.js 14. Embora ainda funcione, prefira remotePatterns, que é mais seguro por permitir a limitação de caminhos específicos.
Por que é preciso definir largura e altura
Com exceção das imagens locais importadas, você precisa informar manualmente width e height para imagens locais e remotas. Isso evita mudanças de layout causadas pelo CLS.
Antes de baixar uma imagem, o navegador precisa saber quanto espaço ela ocupará para reservar essa área. Sem as dimensões, ele só pode reorganizar o layout depois que o download termina, e a página dá um salto.
Talvez você esteja pensando: se a imagem é responsiva e sua largura acompanha a tela, como definir dimensões fixas? A propriedade fill, explicada mais adiante, resolve esse caso.
Como resolver mudanças de layout e otimizar o CLS
Uma página que salta durante o carregamento é realmente desagradável. Em um site de notícias que desenvolvi, a reclamação mais comum dos usuários era: “Eu ia tocar no título, mas a imagem carregou e acabei tocando no anúncio”. Ao estudar melhor o CLS, percebi a importância do problema.
O que é CLS e por que ele importa
CLS significa Cumulative Layout Shift, ou mudança cumulativa de layout. Em termos simples, mede o quanto os elementos mudam repentinamente de posição durante o carregamento da página.
O Google inclui o CLS entre as três métricas centrais dos Core Web Vitals, e ele afeta diretamente o SEO. Uma pontuação acima de 0,1 é considerada ruim; para ser boa, deve ficar abaixo de 0,1. Se uma página contém uma ou duas dezenas de imagens e cada uma desloca o conteúdo ao carregar, o CLS inevitavelmente sobe.
Mais importante ainda é a experiência do usuário. Quando encontro uma página que não para de saltar, normalmente a fecho sem vontade de continuar lendo.
Como o componente Image evita o CLS
O princípio usado pelo componente Image do Next.js é simples: reservar o espaço com antecedência.
Ao definir width e height, o navegador reserva na página uma área vazia com essas dimensões antes mesmo do download. Quando a imagem termina de carregar, ela apenas ocupa esse espaço, sem alterar o layout.
<Image
src="/product.jpg"
width={400}
height={300}
alt="Product image"
/>
Com esse código, o navegador desenha primeiro um espaço de 400 x 300 e só depois começa a carregar a imagem. Assim, o CLS pode chegar a zero.
O desafio é que os sites atuais usam design responsivo, então a largura da imagem precisa acompanhar o tamanho da tela. Dimensões fixas, sozinhas, não bastam.
A forma correta de criar imagens responsivas: a propriedade fill
Para imagens responsivas, o Next.js oferece a propriedade fill. Ela faz a imagem preencher todo o contêiner pai, enquanto a largura e a altura são controladas pelo CSS.
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image
src="/hero.jpg"
fill
style={{ objectFit: 'cover' }}
alt="Hero image"
/>
</div>
Observe três pontos importantes:
- O contêiner pai precisa de
position: relative: assim, a imagem sabe qual elemento deve preencher. - O contêiner pai precisa de uma altura explícita: não pode ser
height: auto; use um valor concreto ou uma porcentagem válida. - Use
objectFitpara controlar o ajuste:coverrecorta a imagem para preencher o contêiner, enquantocontainmostra a imagem inteira, mas pode deixar espaços vazios.
Como o navegador conhece a altura do contêiner pai, consegue reservar o espaço antecipadamente e também evita o CLS.
A propriedade sizes informa ao navegador qual imagem carregar
Quando você usa fill, também deve fornecer a propriedade sizes; caso contrário, o Next.js não sabe qual tamanho gerar.
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image
src="/hero.jpg"
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
style={{ objectFit: 'cover' }}
alt="Hero image"
/>
</div>
A propriedade sizes diz o seguinte:
- Em telas de até 768 px, a imagem ocupa 100% da largura do viewport.
- Entre 768 px e 1200 px, ela ocupa 50% da largura do viewport.
- Acima de 1200 px, ocupa 33% da largura do viewport.
Com essa configuração, o Next.js gera várias dimensões e o navegador escolhe automaticamente a mais adequada. O celular deixa de baixar a enorme versão de desktop, economizando dados e acelerando o carregamento.
Exemplos práticos para cenários diferentes
Imagem Hero, grande e ocupando toda a primeira tela
<div style={{ position: 'relative', width: '100%', height: '60vh' }}>
<Image
src="/hero.jpg"
fill
priority
sizes="100vw"
style={{ objectFit: 'cover' }}
alt="Hero image"
/>
</div>
Aqui, priority, explicada adiante, faz a imagem Hero da primeira tela carregar antes. sizes="100vw" indica que ela sempre ocupa toda a largura do viewport.
Miniatura de artigo, com dimensões fixas
<Image
src={post.thumbnail}
width={300}
height={200}
alt={post.title}
/>
Como as dimensões da miniatura são fixas, usar width e height é a solução mais simples.
Lista de produtos em grade responsiva
<div style={{ position: 'relative', width: '100%', paddingBottom: '100%' }}>
<Image
src={product.image}
fill
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
style={{ objectFit: 'cover' }}
alt={product.name}
/>
</div>
paddingBottom: '100%' cria um contêiner quadrado e responsivo, com proporção 1:1, adequado para fotos de produtos. Em telas diferentes, a imagem ocupa larguras distintas: uma por linha no celular, duas no tablet e três no desktop.
Principais configurações de desempenho
Depois de dominar o uso básico e a otimização do CLS, estas opções ajudam a melhorar ainda mais o desempenho.
priority: dê prioridade às imagens essenciais da primeira tela
Por padrão, as imagens do componente Image usam lazy loading e só começam a carregar quando se aproximam do viewport. No entanto, elementos essenciais da primeira tela, como a imagem Hero e o logotipo, devem aparecer imediatamente para que o usuário não veja uma área vazia.
É aí que entra a propriedade priority:
<Image
src="/hero.jpg"
width={1920}
height={1080}
priority
alt="Hero image"
/>
Ao adicionar priority, o Next.js:
- desativa o lazy loading e inicia o download imediatamente;
- insere uma tag de preload no
<head>do HTML para informar ao navegador que a imagem é importante; - melhora de forma perceptível o LCP (Largest Contentful Paint).
Em uma otimização que fiz, bastou adicionar priority à imagem Hero da página inicial para o LCP cair de 3,8 para 2,1 segundos. O resultado foi imediato.
Quando usar priority?
- Imagem Hero da página inicial.
- Logotipo do site, caso seja grande.
- Imagem principal da página de um artigo.
- Qualquer imagem que possa se tornar o elemento de LCP.
Talvez pareça tentador adicionar priority a todas as imagens, mas não faça isso. A propriedade força o download imediato; se houver 20 imagens com prioridade, o navegador tentará baixar as 20 ao mesmo tempo e o desempenho poderá piorar. Reserve-a apenas para as imagens realmente essenciais.
Mudança no Next.js 16
Também vale mencionar uma mudança do Next.js 16, que no momento é uma versão RC. A propriedade priority será substituída por preload. Se você usa a versão mais recente, escreva:
<Image
src="/hero.jpg"
width={1920}
height={1080}
preload
alt="Hero image"
/>
Ou use a alternativa mais flexível, com loading="eager" e fetchPriority="high":
<Image
src="/hero.jpg"
width={1920}
height={1080}
loading="eager"
fetchPriority="high"
alt="Hero image"
/>
loading: controle a estratégia de carregamento
A propriedade loading aceita dois valores:
lazy, o padrão: a imagem só é baixada quando entra no viewport.eager: a imagem é carregada imediatamente, esteja ou não no viewport.
Na maioria dos casos, o padrão lazy é suficiente. Apenas imagens essenciais da primeira tela precisam de eager.
// Imagem de artigo relacionado no fim da página: use o lazy padrão
<Image src="/related-1.jpg" width={300} height={200} alt="Related post" />
// Imagem principal da primeira tela: use eager
<Image src="/main-content.jpg" width={800} height={600} loading="eager" alt="Main content" />
quality: encontre o equilíbrio entre qualidade e tamanho
A propriedade quality controla a qualidade da compressão em uma escala de 1 a 100. O valor padrão é 75.
<Image
src="/product.jpg"
width={800}
height={600}
quality={90}
alt="Product image"
/>
Quanto maior a qualidade, mais nítida e também maior será a imagem. Estes valores funcionam bem na prática:
- Imagem principal da primeira tela:
quality={90}, para preservar a nitidez. - Imagem comum do conteúdo:
quality={75}, o padrão, para equilibrar qualidade e tamanho. - Miniatura ou plano de fundo:
quality={60}, para economizar largura de banda.
Nos meus testes, reduzir quality de 90 para 75 quase não produziu diferença visível, mas diminuiu o arquivo em cerca de 30%. De 75 para 60, a imagem continuou aceitável em telas comuns e caiu mais 20%.
Atualização importante: a partir do Next.js 16, quality passa a ser obrigatória. A mudança impede que usuários mal-intencionados solicitem muitas variantes de qualidade pelos parâmetros da URL e consumam recursos do servidor. Depois de atualizar para a versão 16, lembre-se de informar quality em cada componente Image.
Seleção automática de formato: WebP ou AVIF
Esse processo é totalmente automático e não exige configuração. O Next.js verifica o cabeçalho Accept do navegador e seleciona o formato mais adequado:
- Navegador aceita AVIF → entrega AVIF, o menor formato, embora a codificação seja mais lenta.
- Navegador aceita WebP → entrega WebP, menor e amplamente compatível.
- Não aceita nenhum dos dois → mantém o formato original, como JPEG ou PNG.
AVIF pode ser de 30% a 40% menor que WebP, embora tenha compatibilidade um pouco inferior. Mesmo assim, os principais navegadores — Chrome 85+, Firefox 93+ e Safari 16+ — já oferecem suporte, então isso raramente é um problema.
Exemplos práticos de configuração
Ao combinar essas opções, você pode tratar cada cenário da seguinte forma.
Imagem Hero da página inicial, com carregamento prioritário e alta qualidade
<div style={{ position: 'relative', width: '100%', height: '60vh' }}>
<Image
src="/hero.jpg"
fill
priority
quality={90}
sizes="100vw"
style={{ objectFit: 'cover' }}
alt="Welcome to our site"
/>
</div>
Miniaturas da lista de artigos, com lazy loading e qualidade intermediária
{posts.map(post => (
<Image
key={post.id}
src={post.thumbnail}
width={300}
height={200}
quality={75}
alt={post.title}
/>
))}
Ícone de link no rodapé, com lazy loading e baixa qualidade
<Image
src="/footer-icon.png"
width={40}
height={40}
quality={60}
alt="Footer icon"
/>
Erros comuns e soluções
Depois de tantos exemplos de uso, vale examinar os problemas mais frequentes no desenvolvimento real. Enfrentei todos eles, e alguns consumiram bastante tempo.
Erro 1: Un-configured Host
Esse é o erro mais comum.
Mensagem de erro:
Error: Invalid src prop (https://example.com/image.jpg) on `next/image`,
hostname "example.com" is not configured under images in your `next.config.js`
Causa:
Você forneceu uma URL externa ao componente Image, mas não incluiu o domínio entre os permitidos em remotePatterns no next.config.js.
Solução:
Adicione a configuração ao next.config.js:
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '/**',
},
],
},
}
Pontos de atenção:
- Reinicie o servidor de desenvolvimento com
npm run devdepois de alterar o arquivo de configuração. - O
hostnameprecisa corresponder exatamente.*.example.comnão funciona; informe cada subdomínio específico. - Se as imagens vierem de vários domínios, adicione mais objetos ao array
remotePatterns.
Erro 2: mudanças de layout ou CLS alto
Sintoma:
Enquanto a página carrega, a imagem aparece de repente, empurra o conteúdo para baixo e faz tudo saltar.
Causa:
Há duas possibilidades:
widtheheightnão foram definidos, então o navegador não sabe quanto espaço reservar.- A propriedade
fillfoi usada, mas o contêiner pai não tem altura.
Solução:
Caso 1: forneça dimensões explícitas.
// ❌ Incorreto: faltam largura e altura
<Image src="/product.jpg" alt="Product" />
// ✅ Correto: largura e altura definidas
<Image src="/product.jpg" width={400} height={300} alt="Product" />
Caso 2: defina a altura do contêiner pai.
// ❌ Incorreto: o contêiner pai não tem altura
<div style={{ position: 'relative', width: '100%' }}>
<Image src="/hero.jpg" fill alt="Hero" />
</div>
// ✅ Correto: o contêiner pai tem altura explícita
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image src="/hero.jpg" fill alt="Hero" />
</div>
Erro 3: imagem desfocada ou grande demais
Sintoma:
No celular, a imagem fica desfocada ou demora muito para carregar.
Causa:
A propriedade sizes não foi configurada. Sem ela, o Next.js não sabe qual tamanho gerar e usa o padrão 100vw, equivalente a toda a largura do viewport. Se a imagem ocupa apenas metade da tela, o arquivo gerado pode ter o dobro do tamanho necessário.
Solução:
Configure sizes de acordo com as dimensões reais de renderização:
// A imagem ocupa larguras diferentes conforme a tela
<Image
src="/product.jpg"
width={400}
height={300}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
alt="Product"
/>
Se a imagem sempre tiver largura fixa, como uma miniatura, basta usar width e height; sizes não é necessário.
Erro 4: uso de APIs descontinuadas
As versões 14 e 15 do Next.js trouxeram mudanças de API. Tutoriais antigos podem usar sintaxes que já foram descontinuadas.
API descontinuada 1: configuração domains
// ❌ Descontinuado no Next.js 14+
module.exports = {
images: {
domains: ['example.com'],
},
}
// ✅ Use remotePatterns
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
],
},
}
API descontinuada 2: callback onLoadingComplete
// ❌ Descontinuado no Next.js 14+
<Image
src="/image.jpg"
width={400}
height={300}
onLoadingComplete={() => console.log('loaded')}
alt="Image"
/>
// ✅ Use onLoad
<Image
src="/image.jpg"
width={400}
height={300}
onLoad={() => console.log('loaded')}
alt="Image"
/>
Mudanças do Next.js 16, que ainda será lançado:
// ⚠️ No Next.js 16, priority será substituída por preload
// Sintaxe antiga, usada até o Next.js 15
<Image src="/hero.jpg" width={1920} height={1080} priority alt="Hero" />
// Nova sintaxe no Next.js 16
<Image src="/hero.jpg" width={1920} height={1080} preload alt="Hero" />
// Ou
<Image src="/hero.jpg" width={1920} height={1080} loading="eager" fetchPriority="high" alt="Hero" />
Checklist rápido para diagnosticar problemas
Quando algo der errado, verifique nesta ordem:
- ✅ Os domínios das imagens remotas estão configurados em
remotePatterns? - ✅ O servidor de desenvolvimento foi reiniciado depois da mudança na configuração?
- ✅ A imagem tem
widtheheight, ou o contêiner pai tem altura? - ✅ Ao usar
fill, o contêiner pai temposition: relativee uma altura explícita? - ✅ Imagens responsivas têm uma propriedade
sizesadequada? - ✅ O código evita APIs descontinuadas, como
domainseonLoadingComplete?
Técnicas avançadas e boas práticas
Depois do uso básico e da correção dos erros comuns, estas técnicas podem melhorar ainda mais a experiência com imagens.
Use placeholder para melhorar a experiência
Imagens levam algum tempo para carregar, especialmente em conexões lentas. Mostrar primeiro uma prévia desfocada torna a espera bem mais agradável.
Blur placeholder, ou espaço reservado desfocado
import Image from 'next/image'
import heroImage from '/public/hero.jpg'
export default function Hero() {
return (
<Image
src={heroImage}
placeholder="blur"
alt="Hero image"
/>
)
}
Quando uma imagem local é importada, o Next.js gera automaticamente uma prévia Base64 de baixa qualidade. Com placeholder="blur", a versão desfocada aparece durante o carregamento e vai dando lugar à imagem nítida. Esse efeito é comum em sites como Instagram e Medium.
Blur placeholder para imagens remotas
No caso de imagens remotas, você precisa fornecer blurDataURL manualmente:
<Image
src="https://example.com/image.jpg"
width={800}
height={600}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
alt="Remote image"
/>
Você pode gerar a blurDataURL com esta ferramenta online ou no servidor, usando a biblioteca sharp.
Empty placeholder
Se você não precisa de um efeito de espera, pode definir explicitamente placeholder="empty". Assim, a área permanece vazia até a imagem carregar. Esse já é o comportamento padrão, portanto omitir a propriedade produz o mesmo resultado.
Integração com uma CDN
Por padrão, o Next.js usa a própria Image Optimization API. Se você utiliza serviços de CDN de imagens, como Cloudinary ou Uploadcare, pode configurar um loader personalizado.
// next.config.js
module.exports = {
images: {
loader: 'cloudinary',
path: 'https://res.cloudinary.com/your-cloud-name/',
},
}
Outra opção é escrever sua própria função de loader:
// next.config.js
module.exports = {
images: {
loader: 'custom',
loaderFile: './my-loader.js',
},
}
// my-loader.js
export default function myLoader({ src, width, quality }) {
return `https://cdn.example.com/${src}?w=${width}&q=${quality || 75}`
}
Dessa forma, todas as requisições de imagem passam pela sua CDN, e não pelo servidor Next.js. É uma boa opção para sites com tráfego elevado.
Uma solução completa para imagens responsivas
Responsividade não significa apenas redimensionar: é preciso considerar como a imagem será apresentada em cada contexto.
Estratégia diferente para celular, tablet e desktop
<div className="image-container">
<Image
src="/product.jpg"
width={1200}
height={800}
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
style={{
width: '100%',
height: 'auto',
}}
alt="Product image"
/>
</div>
Use em conjunto com este CSS:
.image-container {
width: 100%;
}
@media (min-width: 640px) {
.image-container {
width: 50%;
}
}
@media (min-width: 1024px) {
.image-container {
width: 33.333%;
}
}
Quando a propriedade sizes e as media queries do CSS seguem os mesmos valores, o navegador consegue escolher a dimensão mais adequada.
Monitoramento e depuração
Verifique o carregamento de imagens no Chrome DevTools
Abra o Chrome DevTools, acesse a aba Network e marque o filtro Img. Ali, você pode conferir para cada imagem:
- tamanho do arquivo;
- tempo de carregamento;
- cabeçalhos da resposta, incluindo informações sobre o formato.
As URLs das imagens tratadas pelo componente Image incluem parâmetros como ?w=xxx&q=xxx, que mostram a otimização feita pelo Next.js.
Teste de desempenho com o Lighthouse
No Chrome DevTools, abra Lighthouse e clique em “Analyze page load”. Observe principalmente estas métricas:
- LCP (Largest Contentful Paint): o valor ideal é inferior a 2,5 segundos.
- CLS (Cumulative Layout Shift): o valor ideal é inferior a 0,1.
- Sugestões para elementos Image: o Lighthouse indica quais imagens ainda não estão bem otimizadas.
Sempre que termino uma otimização de imagens, executo o Lighthouse para medir o ganho. Em geral, a pontuação sai da faixa dos 60 e passa de 90.
Monitoramento contínuo dos Core Web Vitals
Em produção, vale usar o Google Search Console ou o Vercel Analytics para acompanhar continuamente os Core Web Vitals. Assim, você identifica rapidamente qualquer regressão de desempenho.
Conclusão
Depois de tudo isso, a ideia central do componente Image do Next.js é resolver três problemas: carregamento lento, erros de configuração e mudanças de layout.
Usando o componente Image corretamente, você pode obter:
- redução de 60% a 80% no tamanho das imagens graças à conversão automática para WebP/AVIF;
- LCP abaixo de 2,5 segundos com o uso adequado de
priority; - CLS próximo de zero ao definir dimensões ou usar
fillcorretamente.
Estas são as configurações essenciais:
- Configure imagens remotas em
remotePatternse reinicie o servidor depois da alteração. - Defina
widtheheight, ou usefillcom uma altura no contêiner pai. - Adicione
priorityàs imagens essenciais da primeira tela e mantenha o lazy loading padrão nas demais. - Configure
sizesnas imagens responsivas para o navegador escolher a dimensão correta. - Ajuste
qualityconforme a importância: 90 na primeira tela, 75 para imagens comuns e 60 para miniaturas.
Agora, revise seu projeto e substitua as tags <img> por <Image>. Rode o Lighthouse e confira quanto a pontuação melhorou. Aposto que o ganho será de pelo menos 20 pontos.
Se surgir algum problema, volte à seção de erros comuns deste artigo. A maioria das respostas estará ali. O componente Image do Next.js oferece muitas opções, mas dominar as principais já é suficiente para quase todos os casos.
Fluxo completo para otimizar o componente Image do Next.js
Etapas completas, da configuração de imagens remotas à otimização de desempenho e prevenção de mudanças de layout
⏱️ Estimated time: 2 hr
- 1
Step 1: Configurar domínios de imagens remotas
Configure em next.config.js:
• Adicione o array images.remotePatterns
• Defina protocol, hostname e pathname
• Use curingas quando necessário
Exemplo:
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
pathname: '/images/**'
}
]
}
Atenção: reinicie o servidor de desenvolvimento depois de alterar a configuração - 2
Step 2: Substituir tags img pelo componente Image
Uso básico:
• Importe: import Image from 'next/image'
• Defina width e height, ou use fill
• Adicione texto alt, necessário para SEO
Exemplo:
<Image
src="/hero.jpg"
width={800}
height={600}
alt="Texto descritivo"
/> - 3
Step 3: Evitar mudanças de layout (CLS)
Método 1: defina dimensões fixas
• Informe width e height
• Use aspect-ratio para manter a proporção
Método 2: use o modo fill
• Defina position: relative no contêiner pai
• Use a propriedade fill no componente Image
• Defina largura e altura no contêiner pai
Método 3: use placeholder
• blurDataURL: imagem de espaço reservado desfocada
• placeholder="blur": exibe o espaço reservado - 4
Step 4: Otimizar o desempenho de carregamento
Imagens essenciais da primeira tela:
• Adicione a propriedade priority
• Defina quality=90
• Confirme que a imagem aparece no viewport
Outras imagens:
• O carregamento preguiçoso é padrão e não exige configuração
• Use quality=75 para equilibrar qualidade e tamanho
• Use sizes para obter responsividade
Miniaturas:
• quality=60 costuma ser suficiente
• Use uma versão de dimensões menores - 5
Step 5: Configurar imagens responsivas
Use a propriedade sizes:
• Informe ao navegador o tamanho necessário em cada largura de tela
• O navegador escolhe automaticamente a imagem mais adequada
Exemplo:
<Image
src="/hero.jpg"
width={1200}
height={630}
sizes="(max-width: 768px) 100vw, 50vw"
alt="Descrição"
/>
Assim, o celular carrega uma imagem com largura total e o desktop carrega uma com 50% da largura - 6
Step 6: Testar e validar
Teste de desempenho:
• Use o Lighthouse para medir LCP e CLS
• Verifique o carregamento das imagens na aba Network
• Confirme o formato das imagens, como WebP ou AVIF
Checklist:
• Todos os domínios de imagens remotas estão configurados
• Todas as imagens têm width e height
• As imagens da primeira tela usam priority
• A pontuação de CLS está próxima de 0
• O tamanho das imagens diminuiu pelo menos 60%
FAQ
Por que imagens remotas geram o erro 'Un-configured Host'?
O componente Image exige width e height?
Como evitar mudanças de layout durante o carregamento das imagens?
Quando devo usar a propriedade priority?
O componente Image converte o formato das imagens automaticamente?
Para que serve a propriedade sizes?
Como otimizar a qualidade das imagens?
21 min de leitura · Publicado em: 19 dez 2025 · Atualizado em: 8 set 2026
Guia completo Next.js
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Guia de gerenciamento de estado no Next.js: Zustand vs Jotai na prática
Redux é pesado demais e Context tem problemas de desempenho? Este artigo compara Zustand e Jotai no Next.js e apresenta um guia claro de escolha e boas práticas para o App Router.
Parte 15 de 26
Próximo
Configuração avançada de TypeScript no Next.js: otimize o tsconfig e aumente a segurança de tipos
Aprenda a otimizar o TypeScript no Next.js com modo strict no tsconfig, rotas type-safe e tipagem de variáveis de ambiente para eliminar o uso de any e melhorar a experiência de desenvolvimento.
Parte 17 de 26



Comentários
Entre com GitHub para comentar