astro:assets

[check: …]
📖 Full guide → 📖 ASTRO_ASSETS_OPTIMIZATION.md — the complete narrative, code samples, and verified sources. This page is its interactive companion.

The build-time rule

Import an image from src/assets/ and render it with <Image /> or <Picture /> → Astro optimizes it at build time: it resizes to a responsive width set, converts to modern avif/webp, and emits a responsive srcset + width/height (no CLS) + loading="lazy". The browser then downloads only the variant it needs.

Images in public/ and plain <img> tags bypass this entirely — they are copied as-is, never optimized. This matters most for content sites: a raw hero PNG is often the Largest Contentful Paint (LCP) element, and shipping 2 MB to a 360px phone is pure waste.

import from src/ → optimized default output = .webp <Picture> → avif + webp + fallback constrained layout → 7 srcset variants remote images → must allow domains

Before vs after — the payload story

One source image: a 1600×900 hero PNG. On the left it is served raw (what a plain <img> in public/ ships to every device). On the right, astro:assets has resized + converted it at build time. Drag the viewport / DPR below the panels to see which variant the browser picks.

Before — raw <img> in public/ unoptimized

🖼️ hero.png · 1600×900 · served as-is
Payload (this device)2048 KB
Always the full 2 MB file, regardless of screen.
<!-- copied to dist/ verbatim, no srcset, no lazy -->
<img src="/hero.png">

After — <Picture> from src/assets/ optimized

🛠️ avif 640w · auto-picked
Payload (this device, avif)— KB
Picks the smallest variant ≥ display × DPR.
Saved vs raw
<!-- emitted by astro:assets at build (constrained, 1600-wide source) -->
<picture>
  <source type="image/avif" srcset="...640w, ...750w, ...800w, ...828w, ...1080w, ...1280w, ...1600w">
  <source type="image/webp" srcset="...640w, ...750w, ...800w, ...828w, ...1080w, ...1280w, ...1600w">
  <img src="/_astro/hero.hash.png" width="1600" height="900"
       loading="lazy" decoding="async" alt="Hero">
</picture>
Viewport (CSS px)320 px
constrained sizes = (min-width: 800px) 800px, 100vw → effective display width = 320 px → needs ≈ 320 device px
640w · avif 70 KB · webp 115 KB · vs raw 2048 KB → save 97%

The optimized variant set (the curated demo data)

These are the exact widths the Astro docs show for a constrained layout on a 1600-wide source. Per-variant sizes are a deterministic simulation (a single .html cannot run Sharp): webp ≈ width × 0.18 KB, avif ≈ width × 0.11 KB. The optimizer caps at the source width and never upscales.

Comparison — <Image> vs <Picture> vs plain <img>

This bundle is HOW images are optimized in Astro: import from src/, render with <Image/>/<Picture/>, get resize + avif/webp + responsive srcset + lazy at build time. Cross-refs: 🔗 astro_content_collections (collection image() schema wires cover images into this optimizer) · 🔗 astro_islands (content is static HTML — image work happens at build, not in JS).