Otimização de Imagens
Sirva imagens otimizadas e responsivas com next/image -- conversão automática de formato, carregamento preguiçoso e dicas de tamanho.
Busque em todas as páginas da documentação
Sirva imagens otimizadas e responsivas com next/image -- conversão automática de formato, carregamento preguiçoso e dicas de tamanho.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida -- pronto para copiar e colar.
import Image from "next/image";
// Imagem local (largura/altura automáticas a partir da importação)
import heroImage from "@/public/hero.jpg";
<Image src={heroImage} alt="Banner principal" priority />
// Imagem remota (deve especificar largura e altura)
<Image
src="https://cdn.example.com/photo.jpg"
alt="Foto do produto"
width={800}
height={600}
/>
// Preenche o contêiner (responsivo, sem dimensões explícitas)
<div className="relative h-64 w-full">
<Image
src="/banner.jpg"
alt="Banner"
fill
className="object-cover"
sizes="100vw"
/>
</div>Quando usar isso: Sempre que você renderizar uma imagem. next/image lida com carregamento preguiçoso, conversão de formato (WebP/AVIF), dimensionamento responsivo e prevenção de CLS prontos para uso.
// app/gallery/page.tsx
import Image from "next/image";
type Photo = {
id: string;
url: string;
alt: string;
width: number;
height: number;
};
async function getPhotos(): Promise<Photo[]> {
const res = await fetch("https://api.example.com/photos", {
next: { revalidate: 3600 },
});
return res.json();
}
export default async function GalleryPage() {
const photos = await getPhotos();
return (
<main className="max-w-6xl mx-auto p-6">
<h1 className="text-3xl font-bold mb-8">Galeria</h1>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
{photos.map((photo, index) => (
<div key={photo.id} className="relative aspect-[4/3]">
<Image
src={photo.url}
alt={photo.alt}
fill
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
className="object-cover rounded-lg"
priority={index < 3} // prioriza imagens acima da dobra
/>
</div>
))}
</div>
</main>
);
}// app/components/product-card.tsx
import Image from "next/image";
import Link from "next/link";
type Product = {
slug: string;
name: string;
price: number;
imageUrl: string;
};
export function ProductCard({ product }: { product: Product }) {
return (
<Link
href={`/products/${product.slug}`}
className="group block border rounded-lg overflow-hidden"
>
<div className="relative aspect-square bg-gray-50">
<Image
src={product.imageUrl}
alt={product.name}
fill
sizes="(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw"
className="object-contain group-hover:scale-105 transition-transform"
/>
</div>
<div className="p-4">
<h3 className="font-medium">{product.name}</h3>
<p className="text-gray-600">${product.price.toFixed(2)}</p>
</div>
</Link>
);
}// next.config.ts -- configura domínios de imagem remota
import type { NextConfig } from "next";
const config: NextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "cdn.example.com",
pathname: "/images/**",
},
{
protocol: "https",
hostname: "*.unsplash.com",
},
],
formats: ["image/avif", "image/webp"], // prefere AVIF, com fallback para WebP
},
};
export default config;O que isso demonstra:
fill para imagens responsivas em um layout de gradesizes informando ao navegador o quão larga a imagem será em diferentes tamanhos de viewportpriority para imagens acima da dobra (desabilita carregamento preguiçoso, adiciona dica de pré-carregamento)next.config.tsaspect-[4/3] e aspect-square para prevenir CLSnext/image renderiza uma tag <img> com atributos srcset e sizes. O navegador seleciona o melhor tamanho de imagem com base no viewport e na proporção de pixels do dispositivo.priority desabilita o carregamento preguiçoso e adiciona um <link rel="preload"> para imagens LCP.fill faz a imagem preencher seu contêiner pai (o pai deve ser position: relative, absolute ou fixed). Use isso quando você não conhece as dimensões da imagem no momento da compilação.width e height definem a proporção intrínseca para prevenir Cumulative Layout Shift (CLS). Elas não definem o tamanho renderizado -- use CSS para isso.Imagem responsiva com breakpoints explícitos:
<Image
src="/hero.jpg"
alt="Principal"
width={1200}
height={600}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 1200px"
className="w-full h-auto"
/>Placeholder de desfoque (imagens locais):
import heroImg from "@/public/hero.jpg";
<Image
src={heroImg}
alt="Principal"
placeholder="blur" // gera automaticamente blurDataURL para imagens locais
/>Placeholder de desfoque (imagens remotas):
<Image
src="https://cdn.example.com/photo.jpg"
alt="Foto"
width={800}
height={600}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQ..." // deve ser fornecido manualmente
/>Desabilitando otimização (SVGs, GIFs animados):
<Image
src="/logo.svg"
alt="Logo"
width={200}
height={50}
unoptimized // serve o arquivo original como está
/>import Image, { type ImageProps } from "next/image";
// Estendendo props de Image
type AvatarProps = Omit<ImageProps, "alt"> & {
name: string;
};
function Avatar({ name, ...props }: AvatarProps) {
return (
<Image
alt={`Avatar para ${name}`}
className="rounded-full"
{...props}
/>
);
}
// Tipo StaticImageData para imagens importadas
import type { StaticImageData } from "next/image";
import fallback from "@/public/fallback.jpg";
function getImage(url?: string): string | StaticImageData {
return url ?? fallback;
}Prop sizes ausente com fill -- Sem sizes, o navegador assume que a imagem tem 100vw de largura, baixando um arquivo desnecessariamente grande. Correção: Sempre forneça uma prop sizes que corresponda ao seu layout CSS.
Imagens remotas exigem remotePatterns -- Usar uma URL remota sem configurar remotePatterns em next.config.ts gera um erro de compilação. Correção: Adicione o nome do host (e opcionalmente o padrão do caminho) a images.remotePatterns.
fill requer um pai posicionado -- Se o elemento pai não tiver position: relative (ou absolute/fixed), a imagem sairá de seu contêiner. Correção: Adicione className="relative" ao pai.
priority em muitas imagens -- Marcar muitas imagens como priority anula o propósito e retarda a página. Correção: Use priority apenas na imagem LCP (geralmente 1-2 imagens acima da dobra).
Largura e altura não controlam o tamanho renderizado -- width={800} height={600} define a proporção intrínseca, não o tamanho exibido. A imagem pode renderizar menor ou maior dependendo do CSS. Correção: Use classes CSS (className) para controlar as dimensões de exibição.
Codificação AVIF é lenta -- AVIF produz arquivos menores, mas leva mais tempo para gerar na primeira requisição. Correção: Aceite a latência de "cold start", ou remova "image/avif" de images.formats se o tempo de resposta for crítico.
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
next/image | Todas as imagens em um aplicativo Next.js (a escolha padrão) | Você precisa de <img> puro por um motivo específico |
Tag <img> nativa | Imagens estáticas simples sem necessidade de otimização | Você deseja WebP/AVIF automáticos, carregamento preguiçoso e srcset |
Elemento <picture> | Você precisa de direção de arte (diferentes cortes em tamanhos diferentes) | O dimensionamento responsivo sozinho é suficiente |
| Cloudinary ou Imgix | Você precisa de transformações avançadas (cortar, marca d'água, detecção de rosto) | A otimização integrada do Next.js é suficiente |
| SVG inline | Ícones e ilustrações que precisam ser estilizados com CSS | Conteúdo fotográfico |
srcset e sizesfill quando você não conhece as dimensões da imagem no momento da compilação (por exemplo, imagens enviadas pelo usuário). A imagem preenche seu contêiner pai.width e height explícitos quando as dimensões são conhecidas. Estes definem a proporção intrínseca, não o tamanho renderizado.<link rel="preload"> para que o navegador a busque imediatamente.width e height definem a proporção intrínseca para prevenção de CLS, não o tamanho renderizado. Use classes CSS (className) para controlar as dimensões de exibição reais.
O elemento pai deve ter position: relative, absolute ou fixed. Adicione className="relative" ao <div> pai.
Sem sizes, o navegador assume que a imagem tem 100vw de largura e baixa um arquivo desnecessariamente grande. Forneça sizes para corresponder ao seu layout CSS:
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"Adicione remotePatterns a next.config.ts:
images: {
remotePatterns: [
{ protocol: "https", hostname: "cdn.example.com", pathname: "/images/**" },
],
}Para imagens remotas, você deve fornecer blurDataURL manualmente (uma imagem minúscula codificada em base64). Imagens locais obtêm geração de desfoque automática com placeholder="blur".
import Image, { type ImageProps } from "next/image";
type AvatarProps = Omit<ImageProps, "alt"> & {
name: string;
};
function Avatar({ name, ...props }: AvatarProps) {
return <Image alt={`Avatar para ${name}`} {...props} />;
}StaticImageData é o tipo retornado ao importar um arquivo de imagem local. Use-o quando uma função ou prop pode aceitar tanto uma importação local quanto uma string de URL:
import type { StaticImageData } from "next/image";
function getImage(url?: string): string | StaticImageData {
return url ?? fallbackImage;
}Use unoptimized para imagens que não devem ser processadas, como SVGs ou GIFs animados. O arquivo é servido como está, sem conversão de formato ou redimensionamento.
AVIF produz arquivos menores, mas a codificação é mais lenta na primeira requisição (cold start). Se o tempo de resposta for crítico, considere remover "image/avif" de images.formats e usar apenas WebP.
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥