Next.js
Images con next/image
Explica next/image, dimensiones, fill, sizes, preload, remotePatterns, caché y accesibilidad para mejorar LCP sin descargar imágenes excesivas.
- Última actualización
- Actualizada
- Nivel
- Fundamentos
Next.js
Explica next/image, dimensiones, fill, sizes, preload, remotePatterns, caché y accesibilidad para mejorar LCP sin descargar imágenes excesivas.
next/image optimiza entrega, dimensiones y carga de imágenes, pero necesita información correcta sobre tamaño visual, fuente y prioridad. Una configuración equivocada puede descargar archivos demasiado grandes, permitir abuso del optimizador o empeorar LCP aunque la imagen “funcione”.
Una imagen sin estrategia puede causar:
Image genera srcset, reserva espacio y usa optimización/lazy loading según props y configuración.
import Image from "next/image";
import avatar from "./avatar.png";
export function Profile() {
return (
<Image
src={avatar}
alt="Avatar ilustrado de Nicolás Garzón"
placeholder="blur"
/>
);
}Next.js conoce width, height y blur metadata durante build para formatos compatibles.
No construyas imports dinámicos a partir de input; el bundler necesita analizarlos.
<Image
src="/images/hero.webp"
alt="Panel de gestión de inventario"
width={1600}
height={900}
/>public/images/hero.webp se sirve desde /images/hero.webp. Width y height expresan dimensiones intrínsecas y permiten inferir aspect ratio; CSS controla tamaño final.
<Image
src={product.imageUrl}
alt={product.name}
width={800}
height={800}
/>Next.js no conoce dimensiones remotas al build, por eso debes proporcionarlas o usar fill.
Configura una allowlist precisa:
const nextConfig: NextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "cdn.example.com",
port: "",
pathname: "/products/**",
search: "",
},
],
},
};Evita hostname: "**". El optimizador podría convertirse en proxy de imágenes arbitrarias, consumir recursos o acceder a hosts no deseados.
<div className="relative aspect-[16/9] overflow-hidden rounded-xl">
<Image
src={imageUrl}
alt={alt}
fill
sizes="(min-width: 1024px) 50vw, 100vw"
className="object-cover"
/>
</div>El padre necesita posición relativa/absolute/fixed y dimensiones. fill no crea altura por sí solo.
Usa object-cover cuando aceptas recorte; object-contain cuando toda la imagen debe verse.
sizes describe cuánto ancho ocupa la imagen en viewport:
(min-width: 1024px) 50vw, 100vwEl navegador elige un candidato del srcset.
Sin sizes en una imagen responsive con fill, puede asumir 100vw y descargar un recurso mucho mayor.
Ejemplos:
// Card grid: 3 columns desktop, 2 tablet, 1 mobile
sizes="(min-width: 1280px) 33vw, (min-width: 768px) 50vw, 100vw"Debes alinear sizes con el CSS real. Cambiar layout sin actualizarlo produce desperdicio.
En Next.js 16, priority está deprecado a favor de preload:
<Image
src={hero}
alt="Dashboard de DomiSys"
preload
sizes="100vw"
/>Úsalo solo para la imagen que probablemente será LCP y aparece above the fold.
No preloads:
Demasiados preloads compiten con CSS, fuentes y JavaScript.
Alternativas:
loading="eager" para carga inmediata sin link preload.fetchPriority="high" cuando quieres priorizar el fetch.La documentación recomienda elegir según el caso; no combines preload con loading o fetchPriority sin entender la duplicación.
Por defecto, imágenes no prioritarias usan lazy loading nativo. No significa que nunca se descarguen hasta ser visibles; el navegador usa un umbral.
No lazy-load la imagen LCP. Sí lazy-load galerías y contenido inferior.
<Image
src={image}
alt={alt}
placeholder="blur"
blurDataURL={remoteBlurDataUrl}
/>Para imports estáticos compatibles, blur puede generarse automáticamente. Para remotas debes proporcionar una data URL pequeña.
Un blur grande aumenta HTML. Evita placeholders detallados o de varios KB.
Describe propósito:
alt="Gráfico de ventas mensuales con tendencia ascendente"alt=""No repitas “imagen de”. No uses filename. Si el texto adyacente ya comunica exactamente lo mismo y la imagen no añade información, puede ser decorativa.
En cards enlazadas, evita duplicar el nombre accesible de forma confusa; prueba la composición completa.
quality controla compresión permitida. En Next.js 16, configura qualities permitidas si necesitas valores distintos:
images: {
qualities: [50, 75, 90],
}Más calidad no siempre mejora percepción; aumenta bytes. Usa AVIF/WebP según soporte y coste de encoding.
AVIF puede ser más pequeño, pero tarda más en codificar en cold cache. Mide la plataforma.
Un loader custom genera URLs para un proveedor:
export default function imageLoader({ src, width, quality }: ImageLoaderProps) {
return `https://cdn.example.com/${src}?w=${width}&q=${quality ?? 75}`;
}Configura loaderFile o loader por imagen. El proveedor debe:
No uses loader custom solo para cambiar el hostname.
SVG puede contener scripts o referencias. Next.js no lo optimiza como raster por defecto.
Para SVG remoto:
dangerouslyAllowSVG, añade CSP y Content-Disposition seguros.Para iconos propios, importar como componente mediante tooling puede ser apropiado, pero no es comportamiento automático de Next.js.
El optimizador no reenvía headers arbitrarios del navegador. Una URL protegida por Authorization puede fallar.
Opciones:
unoptimized cuando el origen entrega tamaño correcto.No expongas un bucket privado mediante remotePatterns público.
<Image src={url} alt={alt} width={w} height={h} unoptimized />Útil para GIF animado, SVG o CDN que ya optimiza. Pierdes resizing/formats del optimizador Next.js.
No lo uses globalmente para evitar configurar hosts.
La URL optimizada se cachea según minimumCacheTTL y headers del origen. Next.js no invalida automáticamente archivos remotos cuando cambian bajo la misma URL.
Usa URLs versionadas/content hashes o TTL adecuado.
Un TTL largo mejora hit ratio, pero mantiene imágenes obsoletas.
El optimizador requiere librería y capacidad de CPU. En producción self-hosted instala sharp según la documentación.
Escala/cacha el endpoint /_next/image y no permitas que una CDN elimine query params necesarios.
Con múltiples réplicas, una caché externa/CDN evita repetir transforms.
El optimizador runtime no está disponible por defecto en output: "export". Usa un loader custom/CDN o unoptimized.
Controlan variantes generadas:
deviceSizes: imágenes responsive por viewport.imageSizes: imágenes con sizes que indican tamaños menores.Demasiadas variantes aumentan caché y procesamiento. No personalices sin analizar tus layouts.
Next.js 16 ajustó defaults, por lo que tutoriales antiguos pueden mostrar arrays diferentes.
<article>
<div className="relative aspect-video overflow-hidden rounded-2xl">
<Image
src={project.preview.url}
alt=""
fill
sizes="(min-width: 1280px) 42vw, (min-width: 768px) 50vw, 100vw"
className="object-cover transition-transform duration-700 group-hover:scale-[1.025]"
/>
</div>
<h2>{project.title}</h2>
</article>El alt vacío es correcto si el título adyacente ya describe la card y la preview es decorativa. Si muestra información distinta, crea un alt útil.
La card debe usar un Link real y un área clickeable coherente.
Width/height o aspect ratio reservan espacio. CLS también puede venir de:
fill.La imagen no aparece o colapsa.
Descarga 100vw innecesario.
Contención de red.
Abuso/SSRF indirecto y coste.
No aporta accesibilidad.
Caché obsoleta.
Pierde beneficios sin resolver origen.
Solo define relación intrínseca; CSS puede cambiarla.
fill con contenedor.sizes debe describir el layout real.preload reemplaza a priority en Next.js 16.width=1600 no obliga a mostrar 1600px?sizes en una imagen fill de media columna?preload?Fonts con next/font optimiza otra dependencia crítica del render: tipografía, preload, privacidad y layout shift.