Skip to content
C Codeloom
Astro

Astro Image Component and Optimization

Master Astro's built-in Image and Picture components to ship responsive, lazy-loaded, modern-format images without external services.

·4 min read · By Codeloom
Intermediate 8 min read

What you'll learn

  • How Astro processes local and remote images
  • The difference between Image and Picture components
  • How to ship AVIF and WebP automatically
  • Lazy loading and layout shift prevention
  • When to use a CDN instead

Prerequisites

  • HTML basics
  • An Astro project

What and Why

Images are usually the largest payload on a page. Astro ships an <Image /> and <Picture /> component from astro:assets that handle resizing, format conversion, and lazy loading at build time, without an external service. The result: smaller files, modern formats served to capable browsers, and explicit dimensions that prevent layout shift.

Why does this matter? Because Core Web Vitals reward sites that load fast and stay stable. A 2 MB hero image kills LCP. The same image in AVIF, served at the exact size needed, can drop under 100 KB with no visual loss.

Mental Model

Think of Astro’s image pipeline as a build-time darkroom. You hand it a high-resolution master image. During the build, it develops multiple prints at different widths and formats. Each <img> tag in your HTML points to the right print, and the browser picks the best match based on viewport and capability.

For local images, this happens at build time. For remote images, you must list the allowed domains and the work happens at request time (in SSR) or build time (in static mode).

Hands-on Example

Place an image at src/assets/hero.jpg and import it:

---
import { Image } from 'astro:assets';
import hero from '../assets/hero.jpg';
---
<Image
  src={hero}
  alt="Mountains at sunset"
  width={1200}
  height={600}
  format="avif"
  loading="lazy"
/>

Astro reads the original file, resizes it to 1200x600, converts to AVIF, and emits the optimized file into your dist/_astro folder. The generated HTML includes width and height attributes so the browser reserves space before the bytes arrive.

For multiple formats with a fallback, use <Picture />:

---
import { Picture } from 'astro:assets';
import hero from '../assets/hero.jpg';
---
<Picture
  src={hero}
  alt="Mountains at sunset"
  widths={[400, 800, 1200]}
  formats={['avif', 'webp']}
  sizes="(max-width: 768px) 100vw, 1200px"
/>

This emits a <picture> element with multiple <source> tags. The browser picks the smallest viable file.

src/assets/hero.jpg  (3 MB original)
      |
      v
+---------------------+
|   Astro asset       |
|   pipeline (sharp)  |
+---------------------+
 |     |     |
 v     v     v
400w  800w  1200w
 |     |     |
 +-----+-----+
       |
 avif + webp
       |
       v
 <picture> tag
 with srcset
       |
       v
 browser picks
 best variant
How Astro processes an image at build time

For remote images, configure allowed domains in astro.config.mjs:

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

Common Pitfalls

  • Importing from the public folder. Files in public/ are copied as-is and skipped by the optimizer. Put images in src/ to get processing.
  • Missing width or height. Without dimensions, you cause cumulative layout shift. Astro warns but still emits.
  • Forgetting alt text. Astro requires alt. Use an empty string for purely decorative images.
  • Over-optimizing. Generating dozens of widths bloats your build output and hosting bill. Stick to 3 to 5 sensible breakpoints.
  • Remote images without domain allowlist. They fail loudly in production.

Best Practices

  • Always import images into the page; never reference them as strings.
  • Set loading="lazy" for below-the-fold images and loading="eager" for the hero.
  • Use <Picture /> with both AVIF and WebP for the best compression and compatibility.
  • Provide a meaningful sizes attribute so the browser picks correctly.
  • Run a Lighthouse audit after launch to confirm the optimizations actually shipped.
  • For huge libraries of user-uploaded images, consider a CDN like Cloudinary; Astro is best for content you ship with the site.

Wrap-up

Astro’s image components turn one of the messiest parts of web performance into a tidy declarative API. You import an image, set a few attributes, and the build produces modern formats, responsive variants, and stable layouts. For most projects, you can delete your image CDN bill and let the static pipeline handle it. Combine <Picture />, explicit dimensions, and lazy loading, and your Lighthouse scores will reflect the effort almost immediately.