Optimizar imágenes en Astro
Daniel Villegas

Daniel Villegas

Desarrollador Front-end

Volver atrás
Lab

4 min de lectura

4 de marzo de 2026

Optimizar imágenes en Astro: el problema que ya estaba resuelto

WebP, srcset, versiones para móvil, evitar layout shift… optimizar imágenes en una landing suele implicar más trabajo del que parece. En Astro, gran parte de ese proceso puede simplificarse mucho más de lo habitual.

El ritual de optimizar imágenes en una landing

Cada vez que creaba una nueva landing page y tenía que incluir imágenes me enfrentaba siempre al mismo ritual: exportar la imágenes en webp con cweb o Squoosh, generar variantes para móvil y escritorio, escribir el srcset a mano, acordarme de los tamaños y rezar para que no se me olvidase el loading=’lazy’. Todo eso para una sola imagen.

Funcionar, funcionaba, pero era lento, manual y cada vez que el cliente quería cambiar la imagen por otra diferente el proceso empezaba de nuevo.

Cuando monté mi última landing con Astro encontré en la documentación el componente <Image /> casi por accidente. Lo probé por curiosidad y fue una de esas veces en las que te sientes un poco inútil por no haberlo visto antes.

El problema del código manual

Mi código antes de usar <Image /> era:

<picture>
  <source
    srcset="/images/hero-800.webp 800w, /images/hero-1200.webp 1200w"
    type="image/webp"
  />
  <source
    srcset="/images/hero-800.jpg 800w, /images/hero-1200.jpg 1200w"
    type="image/jpeg"
  />
  <img
    src="/images/hero-1200.jpg"
    alt="Descripción"
    loading="lazy"
    width="1200"
    height="630"
  />
</picture>


Y eso asumiendo que no me dejaba algo por el camino. El width y height para evitar el layout shift, el fallback en JPEG, los dos srcset. Un error y la imagen o bien no cargaba en móvil o el CLS se disparaba en el Lighthouse.

Optimizar imágenes con Astro

Mi código con <Image /> en Astro ahora es:

---
import { Image } from 'astro:assets';
import hero from '../assets/hero.jpg';
---

<Image src={hero} alt="Descripción" width={1200} height={630} />


Sí, eso es todo. Por detrás Astro convierte la imagen a WebP automáticamente, genera el width y height para evitar el layout shift y añade loading="lazy" por defecto.

Lo que más me sorprendió fue el HTML resultante, y es que el componente envía exactamente lo que necesitas: únicamente envía el output que antes tenía que escribir a mano y donde había más posibilidad de error humano.

Imágenes externas en Astro

Una cosa a tener en cuenta es que esto funciona con imágenes locales, las que tienes dentro del proyecto. Si en algún caso se necesitan cargar imágenes desde una URL externa, tendrás que declarar los dominios en el archivo de configuración de Astro, astro.config.mjs. En una landing normal no suele ser el caso, pero es algo que conviene saber antes de que te explote en la cara.

Configurar dominios fijos

Ejemplo para dominios fijos:

// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  image: {
    domains: ['images.dominio.com', 'cdn.dominio.com'],
  },
});

Configurar CDN con subdominios dinámicos

Otro para dominios que no son fijos, como por ejemplo una CDN con subdominios dinámicos:

export default defineConfig({
  image: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: '**.dominio.com', // El ** cubre cualquier subdominio
      },
    ],
  },
});


Sin esta configuración, Astro rechaza la imagen por seguridad y lanza un error en construcción.

Cuando el hero cambia en móvil

Para la mayoría de imágenes lo anterior es más que suficiente. Pero hay un caso bastante habitual que <Image /> no resuelve solo.

A raíz de descubrir <Image /> también descubrí <Picture />, que viene a solucionarte uno de los problemas más comunes: el Hero no suele ser igual en escritorio que en móvil. No suele ser un problema de tamaño, sino de composición.

En escritorio, normalmente, tienes espacio suficiente para una imagen horizontal a la derecha y un texto a la izquierda. En móvil, esa misma imagen queda diminuta o tienes que recortarla, y eso no tiene sentido. Para solucionar esto existe <Picture />.

Ejemplo de uso de <Picture />

Ejemplo de cómo se aplica este componente:

---
import { Picture } from 'astro:assets';
import heroDesktop from '../assets/hero-desktop.jpg';
import heroMobile from '../assets/hero-mobile.jpg';
---

<Picture
  src={heroDesktop}
  alt="Descripción"
  formats={['webp', 'jpg']}
  sources={[
    { src: heroMobile, media: "(max-width: 768px)" }
  ]}
  width={1200}
  height={630}
/>


El navegador carga la imagen según el viewport. Astro optimiza ambas. Y lo mejor es que no tienes que construir el picture a mano.

Cosas importantes a tener en cuenta

  • Si la imagen es de mala calidad, Astro la optimiza pero no la mejora. Seguirá siendo una imagen de mala calidad.
  • Si tu layout es complejo, ya sea porque usas un grid de varias columnas o flex con disposiciones absolutas, es importante que revises el atributo sizes, porque es posible que Astro no te de el más óptimo para tu caso.

El resultado

En mi última landing page con Astro usando todo esto logré un LCP de 0,9 segundos, principalmente porque las imágenes dejaron de llegar al navegador sobredimensionadas.

Es uno de esos casos donde la herramienta correcta no solo resuelve el problema, sino que además elimina la posibilidad de cometer errores.