wandres.dev
IMÁGENES · astro:assets

getImage y los servicios de imagen

La función que hay debajo del componente: getImage optimiza una imagen y te devuelve su src y sus atributos para los casos donde no cabe una etiqueta, como un fondo CSS o la og:image de las tarjetas sociales. Y por debajo de todo, el servicio de imagen que hace el trabajo real: Sharp como motor por defecto, Squoosh como opción heredada, y las pasarelas que delegan la transformación en un CDN o plataforma.

⏱ 17 min

<Image /> y <Picture /> cubren el noventa por ciento de los casos, pero hay lugares donde una etiqueta no cabe: el background-image de una hoja de estilos, la og:image que va en una <meta>, un manifiesto, un correo. Para todos ellos existe getImage, la función que hace el trabajo de optimización y te entrega el resultado en crudo —una URL y unos atributos— para que lo coloques donde quieras. Y bajo esa función, y bajo los componentes, opera una pieza que casi nunca ves pero que decide cómo se transforma cada imagen: el servicio de imagen. Esta lección baja esos dos peldaños, del componente a la función y de la función al motor.

🎯 Al terminar esta lección sabrás
  • Usar getImage para optimizar una imagen y obtener su src y sus atributos.
  • Resolver casos sin etiqueta como un fondo CSS o una og:image social.
  • Distinguir los servicios de imagen: Sharp, el heredado Squoosh y las pasarelas.
  • Elegir el servicio según el entorno de despliegue y sus capacidades.

getImage: el motor sin el componente

<Image /> no hace magia propia: por dentro llama a getImage, calcula el resultado y lo pinta como una etiqueta. Si te saltas el componente y llamas tú a esa función, obtienes lo mismo que él usa, pero como datos manipulables en lugar de HTML ya cerrado. Es una función asíncrona: recibe las mismas opciones que las props del componente —src, width, format, quality— y devuelve un objeto con la URL optimizada en src, un attributes con los atributos calculados y un srcSet si procede.

---
import { getImage } from 'astro:assets';
import hero from '../assets/hero.png';
const optimizada = await getImage({ src: hero, width: 800, format: 'webp' });
---
<img src={optimizada.src} width={optimizada.attributes.width} alt="Puerto" />

Ese optimizada.src es la ruta al fichero ya transformado que Astro emitirá; el resto del objeto son los metadatos con los que armar la etiqueta que necesites. Con getImage recuperas el control fino a cambio de escribir a mano lo que el componente te daba hecho.

Dónde brilla: fondos CSS y og:image

El primer caso claro es un fondo. No puedes poner un <Image /> dentro de background-image, pero sí puedes pedirle a getImage la URL optimizada y volcarla en el estilo. Así una imagen decorativa de fondo se beneficia del mismo reencode y redimensionado que cualquier otra.

---
import { getImage } from 'astro:assets';
import fondo from '../assets/fondo.jpg';
const bg = await getImage({ src: fondo, width: 1920, format: 'webp' });
---
<section style={`background-image: url(${bg.src})`}>
  <h1>Portada</h1>
</section>

El segundo caso es la imagen de las tarjetas sociales. Al compartir un enlace, las redes leen la <meta property="og:image">, y esa etiqueta exige una URL absoluta: el rastreador vive fuera de tu dominio y una ruta relativa no le sirve de nada. getImage te da la ruta optimizada, y combinándola con Astro.site —la URL de producción declarada en la config— la conviertes en absoluta.

---
import { getImage } from 'astro:assets';
import portada from '../assets/og.png';
const og = await getImage({ src: portada, width: 1200, height: 630, format: 'png' });
const ogUrl = new URL(og.src, Astro.site);
---
<meta property="og:image" content={ogUrl.href} />
💡
og:image quiere absoluta, estable y del tamaño justo

Tres detalles hacen que una tarjeta social funcione. Debe ser absoluta, porque quien la lee no es tu navegador sino un servidor remoto que no conoce tu ruta base. Conviene un tamaño canónico —1200 por 630 es el estándar— para que las plataformas no la recorten mal. Y su URL debe ser estable entre despliegues, para que las vistas previas ya cacheadas no se rompan. getImage con dimensiones fijas y Astro.site cubre los tres.

flowchart TD
GI[getImage con src y opciones] --> RES[objeto con src attributes y srcSet]
RES --> C[url para background-image en CSS]
RES --> O[url absoluta para la og image social]
RES --> M[atributos para un img compuesto a mano]
style GI fill:#89b4fa,color:#11111b
style RES fill:#f9e2af,color:#11111b
style C fill:#a6e3a1,color:#11111b
style O fill:#a6e3a1,color:#11111b
style M fill:#a6e3a1,color:#11111b

El servicio de imagen: quién hace el trabajo

Ni el componente ni getImage transforman los píxeles por sí mismos: delegan en un servicio de imagen, un módulo intercambiable que sabe redimensionar y reencodear. Astro trae uno por defecto y te deja cambiarlo, y esa elección importa cuando el sitio sale del portátil y aterriza en un entorno de despliegue concreto.

El motor por defecto es Sharp, una biblioteca nativa rápida y de gran calidad que resuelve casi cualquier necesidad sin que la toques. Squoosh fue el servicio anterior, escrito en WebAssembly puro y por ello muy portable pero más lento; hoy es una opción heredada, en desuso y retirada de las versiones actuales, que conviene conocer solo para entender configuraciones antiguas. Y en el otro extremo están las pasarelas: servicios que no transforman la imagen en tu build ni en tu servidor, sino que delegan el trabajo en una plataforma o un CDN —Vercel, Netlify, Cloudflare, Cloudinary— que la optimiza bajo demanda en su propia infraestructura. Cambiar de servicio es cambiar una línea.

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

export default defineConfig({
  image: {
    service: sharpImageService(),
  },
});

Hay un caso en que la pasarela o el servicio de paso dejan de ser un lujo y se vuelven necesarios: los entornos donde una biblioteca nativa como Sharp no puede instalarse o ejecutarse, ciertos runtimes de borde o funciones serverless muy restringidas. Allí se usa un servicio de paso que no transforma —confiando la optimización a la plataforma— o directamente el servicio de imágenes que esa plataforma ofrece. La misma llamada a <Image /> de tu código sigue igual; lo que cambia por debajo es quién ejecuta la transformación.

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

export default defineConfig({
  image: {
    service: passthroughImageService(),
  },
});

Un servicio de pasarela de terceros se enchufa igual, apuntando image.service a su punto de entrada y pasándole su configuración. Tu código de plantilla no se entera: sigue escribiendo <Image /> y getImage, y es la plataforma quien recibe las peticiones de transformación y devuelve las imágenes ya optimizadas desde su propia red. Esa indiferencia del código ante el motor es justo lo que hace el sistema portable entre despliegues.

// astro.config.mjs
export default defineConfig({
  image: {
    service: {
      entrypoint: 'mi-proveedor/servicio',
      config: { calidadPorDefecto: 'auto' },
    },
  },
});
🧰

getImage devuelve datos

Optimiza como el componente pero entrega src, attributes y srcSet para colocarlos donde no cabe una etiqueta.

🎨

Fondos y og:image

Un fondo CSS toma su url de src; una og:image la vuelve absoluta con Astro.site para que la lea otro servidor.

⚙️

Sharp por defecto

El motor nativo rápido y de calidad. Squoosh es la opción heredada en WebAssembly, hoy en desuso.

☁️

Pasarelas

Delegan la transformacion en un CDN o plataforma, o usan un servicio de paso donde Sharp no puede correr.

Separar la intención de la maquinaria: la ergonomía por fuera, el mecanismo por dentro

Estas dos piezas —getImage bajo el componente, el servicio bajo getImage— son la misma idea vista en dos capas, y esa idea es de las más fértiles que ofrece un buen diseño de software: separar la intención de la maquinaria que la cumple. Arriba del todo, <Image /> expresa una intención con la máxima comodidad posible: aquí hay una imagen, muéstrala bien. No dice cómo, ni con qué motor, ni en qué formato exacto; solo qué quieres. Un peldaño abajo, getImage desnuda esa comodidad y expone la operación como una función que devuelve datos, para cuando la etiqueta ergonómica no encaja en tu hueco —un fondo, una meta, un manifiesto— y necesitas la primitiva en lugar del envoltorio. Y un peldaño más abajo, el servicio de imagen encarna el cómo puro: el mecanismo concreto que mueve los píxeles, deliberadamente intercambiable, de modo que el mismo código de arriba se ejecute con Sharp en tu máquina, con una pasarela en el borde o con el optimizador de una plataforma, sin que una sola línea de tus páginas lo note. Esa estratificación no es casual; es el patrón que hace que un sistema envejezca bien. Cuando la intención está separada de la implementación, puedes cambiar la maquinaria sin reescribir a quien la usa, y puedes ofrecer una fachada cómoda sin renunciar a una salida de emergencia hacia el nivel de abajo. Los frameworks que perduran son casi siempre los que aciertan con esta doble oferta: una superficie de alto nivel que resuelve el caso común sin fricción, y una primitiva de bajo nivel, accesible cuando la haces falta, que no te abandona en cuanto tu caso se sale del molde. getImage es esa primitiva, el servicio es ese mecanismo enchufable, y el componente es la fachada amable que descansa sobre ambos. Aprende a ver esa escalera en cada herramienta que uses —dónde está la comodidad, dónde la primitiva, dónde el mecanismo sustituible— y sabrás siempre a qué altura bajar cuando el caso fácil deje de bastarte.

⚔️ Baja del componente a la función y al motor
  1. Usa getImage para optimizar una imagen y píntala con un <img> a mano tomando src y las dimensiones de su objeto attributes.
  2. Aplica una imagen optimizada como background-image de una sección leyendo su src, y compara su peso con el del fichero original.
  3. Genera una og:image de 1200 por 630 con getImage, conviértela en URL absoluta con Astro.site y colócala en la <meta>; valida la tarjeta con un depurador social.
  4. Cambia el servicio a passthroughImageService en la config, reconstruye y observa que las imágenes ya no se transforman, razonando en qué entorno de despliegue esa elección tendría sentido.