Next/Image: Optimización automática, lazy loading y placeholders explicados con ejemplos
Introducción
Si estás construyendo una aplicación con Next.js y te preocupa el rendimiento de las imágenes, seguramente ya escuchaste hablar del componente next/image. Este elemento no es solo un <img> cualquiera: incorpora optimizaciones automáticas de tamaño, formato y compresión, además de lazy loading integrado y varios tipos de placeholders que mejoran la experiencia de carga.
En este artículo vas a aprender:
- Qué hace qué hace automáticamente
- cómo funciona lazy loading de forma nativa?
- Qué placeholders están disponibles y cuándo usarlos
- Cómo configurar el componente para diferentes casos de uso
- Qué errores comunes evitar y cuáles son las mejores prácticas
El contenido está pensado para desarrolladores que ya conocen los básicos de Next.js (rutas, páginas, componentes) y quieren profundizar en la optimización de recursos visuales. Al final tendrás ejemplos listos para copiar y pegar, con la salida HTML esperada para que puedas verificar el comportamiento.
¿Qué hace realmente next/image?
Cuando Next.js compila tu proyecto, el componente next/image se transforma en un conjunto de elementos <img> y <picture> que apuntan a versiones optimizadas de la misma imagen. Estas versiones se generan en tiempo de compilación (si la imagen está en el proyecto) o en tiempo de ejecución mediante un servidor de imágenes (el llamado Image Optimizer).
Las optimizaciones incluyen:
- Redimensionamiento automático: se crean múltiples anchuras según el dispositivo y el layout definido.
- Formato moderno: se sirve WebP o AVIF cuando el navegador lo soporta, fallback a JPEG/PNG.
- Compresión inteligente: se ajusta la calidad para equilibrar peso y fidelidad visual.
- Lazy loading: el atributo
loading='lazy'se agrega automáticamente, salvo que indiques lo contrario. - Placeholder opcional: puedes mostrar una versión borrosa, un color dominante o un espacio vacío mientras se carga la imagen real.
Todo esto ocurre sin que tengas que escribir un loader personalizado o configurar un CDN de imágenes por tu cuenta.
Lazy loading incorporado
El lazy loading (carga diferida) pospone la descarga de una imagen hasta que está próxima a entrar al viewport. En navegadores modernos basta con el atributo loading='lazy'. Next.js lo agrega por defecto en todas las imágenes que no tengan la propiedad priority establecida en true.
Esto significa que, si tienes una lista de productos con muchas imágenes, solo las que están visibles se descargan inicialmente; el resto se cargará cuando el usuario haga scroll.
Ejemplo básico
function ImgEjemplo({src, alt, width, height}) {
return `<img src='${src}' alt='${alt}' width='${width}' height='${height}' loading='lazy' style='display:block;max-width:100%;height:auto;' />`;
}
console.log(ImgEjemplo({src:'/producto.jpg', alt:'Zapatillas', width:400, height:300}));Salida esperada:
Si quisieras forzar la carga inmediata (por ejemplo, una imagen hero en la parte superior), usarías priority:
function ImgPrioritaria({src, alt, width, height}) {
return `<img src='${src}' alt='${alt}' width='${width}' height='${height}' loading='eager' style='display:block;max-width:100%;height:auto;' />`;
}
console.log(ImgPrioritaria({src:'/hero.jpg', alt:'Banner principal', width:1200, height:400}));Salida esperada:
Placeholders: mejorar la percepción de velocidad
Mientras la imagen de alta resolución se descarga, es útil mostrar algo que indique que hay contenido cargándose. next/image ofrece tres estrategias de placeholder:
blur– una versión muy pequeña y borrosa de la imagen (generada a partir de un blur up).empty– nessun placeholder; se muestra el espacio vacío hasta que la imagen esté lista.dominantColor– se extrae el color más predominante de la imagen y se usa como fondo sólido.
Además, puedes proveer tu propia imagen borrosa mediante la propiedad blurDataURL (útil cuando la imagen proviene de un CDN externo y no quieres que Next.js la procese).
Placeholder blur
Este es el más común porque da una vista previa suave de la imagen final. Next.js crea automáticamente una imagen de 20px de ancho, la desenfoca y la incruta como base64 dentro del atributo srcset del elemento <img>.
function ImgBlur({src, alt, width, height}) {
// Simulamos el HTML que Next.js generaría
const placeholder = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxISEhUTExIVFRUVFRUWFRUXFRUYFRUWFRUWFRUWFhUVFRUYHSggGBolGxUVITEhJSkrLi4uFx8zODMsNygtLisBCgoKDg0OGxAQGi0lHyUtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLf/AABEIAKAA0AMBIgACEQEDEQH/xAAcAAABBQEBAQAAAAAAAAAAAAAAAQIDBAUGBwj/xABEEAACAQIEBAYHBAUFAQAAAAABAAIDBBEFEiExBkFREyJhcYGRBxQykaEHobFCMzNUYnKCksEVJHNDY4KT/8QAGgEAAwEBAQEAAAAAAAAAAAAAAAECAwQFBv/EACsRAAICAQQCAwEBAAAAAAAAAAABAhEDIRIxQQUTEyJhcZEUobGx0RQjNC/9oADAMBAAIRAxEAPwD9//Z" ;
return `<img src='${placeholder}' alt='${alt}' width='${width}' height='${height}' style='display:block;max-width:100%;height:auto;background-color:#f0f0f0;' />`;
}
console.log(ImgBlur({src:'/paisaje.jpg', alt:'Montañas', width:800, height:450}));Salida esperada (el atributo src contiene la imagen borrosa en base64):
Cuando la imagen real se descarga, Next.js reemplaza el src por la URL optimizada y elimina el estilo de fondo.
Placeholder empty
Si prefieres que no se muestre nada mientras se carga (por ejemplo, en una galería donde el layout ya reserva el espacio), basta con establecer placeholder='empty'.
function ImgEmpty({src, alt, width, height}) {
return `<img src='' alt='${alt}' width='${width}' height='${height}' style='display:block;max-width:100%;height:auto;visibility:hidden;' />`;
}
console.log(ImgEmpty({src:'/icono.png', alt:'Icono', width:100, height:100}));Salida esperada:
En la práctica, Next.js mantiene el atributo src vacío hasta que la imagen esté lista, momento en el cual lo llena con la URL optimizada.
Placeholder dominantColor
Este placeholder extrae el color más predominante de la imagen y lo aplica como fondo del elemento. Es útil cuando el diseño se basa en bloques de color y deseas evitar un destello blanco.
function ImgColor({src, alt, width, height, color}) {
return `<img src='' alt='${alt}' width='${width}' height='${height}' style='display:block;max-width:100%;height:auto;background-color:${color};' />`;
}
console.log(ImgColor({src:'/logo.png', alt:'Logo empresa', width:200, height:80, color:'#2c3e50'}));Salida esperada:
Uso básico del componente
En un archivo .jsx o .tsx de Next.js, el componente se importa así:
import Image from 'next/image';
export default function MiPagina() {
return (
<div>
<Image
src='/foto-perfil.jpg'
alt='Foto de perfil'
width={400}
height={400}
placeholder='blur'
/>
</div>
);
}Las propiedades width y height son obligatorias (excepto cuando usas loader personalizado o fill). Sirven para calcular la relación de aspecto y evitar el layout shift.
Propiedades más usadas
| Propiedad | Descripción | Valor típico |
|---|---|---|
src |
URL de la imagen (puede ser estática o externa) | '/img.jpg' o 'https://ejemplo.com/foto.png' |
alt |
Texto alternativo para accesibilidad | Descripción concisa |
width |
Ancho en píxeles (se usa para generar srcset) | 800 |
height |
Alto en píxeles | 600 |
loader |
Función personalizada que genera la URL de la imagen | ( {src, width, quality} => //mi-cdn.com/${src}?w=${width}&q=${quality} ) |
priority |
Forzar carga inmediata (evita lazy loading) | true/false |
placeholder |
Tipo de placeholder ('blur', 'empty', 'dominantColor') |
'blur' |
blurDataURL |
Imagen borrosa personalizada en base64 (solo con placeholder='blur') |
'data:image/jpeg;base64,....' |
quality |
Nivel de compresión (1-100) | 75 |
sizes |
Anchos relativos para diferentes viewport (como en <img sizes>) |
'(max-width: 768px) 100vw, 33vw' |
style / className |
Estilos CSS adicionales | { borderRadius: '8px' } |
Ejemplos completos con salida HTML esperada
A continuación verás varios escenarios reales. Cada bloque de código contiene una función que devuelve el HTML que Next.js generaría (simplificado) y su salida esperada.
1. Imagen estática con blur y tamaños responsive
function ImgResponsiveBlur({src, alt}) {
// Simulamos srcset con tres ancho: 400, 800, 1200
const srcset = `
${src} 400w,
${src} 800w,
${src} 1200w
`;
const placeholder = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxISEhUTExIVFRUVFRUWFRUXFRUYFRUWFRUWFRUWFhUVFRUYHSggGBolGxUVITEhJSkrLi4uFx8zODMsNygtLisBCgoKDg0OGxAQGi0lHyUtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLf/AABEIAKAA0AMBIgACEQEDEQH/xAAcAAABBQEBAQAAAAAAAAAAAAAAAQIDBAUGBwj/xABEEAACAQIEBAYHBAUFAQAAAAABAAIDBBEFEiExBkFREyJhcYGRBxQykaEHobFCMzNUYnKCksEVJHNDY4KT/8QAGgEAAwEBAQEAAAAAAAAAAAAAAAECAwQFBv/EACsRAAICAQQCAwEBAAAAAAAAAAABAhEDIRIxQQUTEyJhcZEUobGx0RQjNC/9oADAMBAAIRAxEAPwD9//Z" ;
return `<img src='${placeholder}' alt='${alt}' srcset='${srcset}' sizes='(max-width: 600px) 100vw, (max-width: 900px) 50vw, 33vw' style='display:block;max-width:100%;height:auto;' />`;
}
console.log(ImgResponsiveBlur({src:'/producto.jpg', alt:'Producto destacado'}));Salida esperada:
2. Imagen externa con loader personalizado y dominantColor
Supongamos que tus imágenes están en un CDN propio y quieres aplicar el color dominante como placeholder.
function ImgExternoCDN({src, alt, width, height, dominant}) {
// Loader que agrega ancho y calidad al URL
const url = `https://mi-cdn.com/${src}?w=${width}&q=80`;
return `<img src='' alt='${alt}' width='${width}' height='${height}' style='display:block;max-width:100%;height:auto;background-color:${dominant};' />`;
}
console.log(ImgExternoCDN({src:'fotos/viaje.jpg', alt:'Atardecer en la playa', width:1600, height:900, dominant:'#ff6f61'}));Salida esperada:
Cuando la imagen se carga, Next.js remplazará el src vacío por la URL generada por el loader.
3. Imagen de prioridad alta (hero) sin placeholder
function ImgHero({src, alt, width, height}) {
return `<img src='${src}' alt='${alt}' width='${width}' height='${height}' loading='eager' style='display:block;max-width:100%;height:auto;' />`;
}
console.log(ImgHero({src:'/hero.jpg', alt:'Titular principal', width:1920, height:1080}));Salida esperada:
Configuración avanzada en next.config.js
Para afinar el comportamiento global de next/image puedes editar el archivo next.config.js. Algunas opciones útiles:
domains: lista de dominios externos permitidos para cargar imágenes sin necesidad de un loader personalizado.deviceSizes: arreglo de anchos (en píxeles) que Next.js considerará al generar srcset para dispositivos típicos.imageSizes: arreglo de anchos para imágenes que no son de layout full‑width (por ejemplo, thumbnails).path: permite cambiar el endpoint interno del Image Optimizer (por defecto/_next/image).
Ejemplo de configuración:
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
domains: ['images.unsplash.com', 'cdn.mi-sitio.com'],
deviceSizes: [640, 768, 1024, 1280, 1600],
imageSizes: [32, 48, 64, 96],
path: '/_next/image',
dangerouslyAllowSVG: true,
contentDispositionType: 'attachment',
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;"
},
};
export default nextConfig;Con esta configuración, cualquier imagen cuyo src sea una URL completa que incluya uno de los dominios listados será optimizada automáticamente por el Image Optimizer de Next.js, aplicando los mismos principios de resize, formato y calidad.
Buenas prácticas
- Siempre especifica
widthyheight(excepto cuando usasfillo un loader personalizado que maneje el aspecto). Esto evita el layout shift y mejora la puntuación de Core Web Vitals. - Usa
prioritysolo en imágenes por encima del doblez (hero, banners, logos principales). Sobrecargar deprioritypuede empeorar el rendimiento porque el navegador descarga imágenes que aún no se ven. - Prefiere
placeholder='blur'para imágenes de contenido donde la vista previa ayuda a la percepción de velocidad. Evita usarlo en iconos muy pequeños porque el costo de generar la versión borrosa puede superar el beneficio. - Optimiza el tamaño de las imágenes fuente antes de subirlas al repositorio. Next.js no hará milagros si la imagen original pesa 5 MB; lo mejor es comenzar con un archivo razonable (menos de 1 MB) y dejar que el optimizador ajuste la calidad.
- Controla los dominios externos en
next.config.js. No dejes la lista vacía si vas a cargar imágenes de CDNs conocidos; de lo contrario Next.js bloqueará la petición por seguridad. - Prueba con diferentes conexiones (por ejemplo, usando las herramientas de Chrome DevTools → Network → throttling) para asegurarte de que el lazy loading y los placeholders se comportan como esperas en redes lentas.
- Monitorea el uso del Image Optimizer en producción. Si notas un aumento inesperado en el tiempo de respuesta del servidor, revisa si estás generando muchas variantes de tamaños innecesarios; ajusta
deviceSizesyimageSizessegún tu audiencia.
Errores comunes
- Olvidar
widthyheight: provoca que el elemento tenga dimensiones 0×0 hasta que la imagen cargue, causando desplazamientos de layout. - Usar
placeholder='blur'en imágenes SVG: el blur de un SVG no se genera correctamente; mejor usarplaceholder='dominantColor'oempty. - Cargar imágenes externas sin agregar el dominio a
next.config.js: Next.js devuelve un error 400 y la imagen no se muestra. - Establecer
priorityen todas las imágenes: pierde el beneficio del lazy loading y puede afectar el LCP (Largest Contentful Paint). - Sobrecargar el
qualitya valores muy bajos (ej. 10): aunque reduce el peso, la imagen se ve pixelada y afecta la percepción de marca. - No limpiar
blurDataURLcuando cambias la imagen: si usas un blurDataURL estático y la imagen real cambia, el placeholder puede no coincidir con el tono de la nueva imagen, provocando un salto visual desagradable.
Conclusión
El componente next/image es una herramienta poderosa que encapsula en una sola API varias técnicas de optimización de imágenes que, de otro modo, requerirían configuraciones complejas y herramientas externas. Gracias a su optimización automática de tamaños y formatos, su lazy loading incorporado y sus placeholders flexibles, puedes mejorar significativamente el rendimiento de tus aplicaciones Next.js sin sacrificar la calidad visual.
En este artículo viste:
- cómo funciona el Image Optimizer detrás de escena,
- qué significa el lazy loading y cómo forzar la carga inmediata cuando es necesario,
- cuáles son los tipos de placeholders disponibles y cuándo cada uno resulta útil,
- ejemplos prácticos con el HTML que Next.js genera y su salida esperada,
- y finalmente, una lista de buenas prácticas y errores típicos para que puedas aplicar lo aprendido de forma segura en tus proyectos.
Con esta información, estás listo para revisar tu código existente, añadir width y height donde falten, elegir el placeholder adecuado para cada caso y ajustar la configuración de next.config.js según el origen de tus imágenes. Así podrás ofrecer una experiencia más rápida, estable y agradable a tus usuarios.
Próximos pasos
Si deseas seguir profundizando, te recomiendo:
- Leer la documentación oficial de Next.js sobre Image Optimization (https://nextjs.org/docs/api-reference/next/image).
- Experimentar con un loader personalizado que se integre con un servicio de transformación de imágenes como Cloudinary o Imgix.
- Auditar las imágenes de tu proyecto con herramientas como Lighthouse o Web Vitals para medir el impacto de los cambios realizados.
- Explorar el uso del componente
next/future/image(experimental) que trae mejoras en el manejo desrcsetysizes.
¡Manos a la obra y que tus imágenes carguen siempre a la velocidad de la luz!
DUGLAS MORENO
Comentarios (0)
Sé el primero en comentar.