For Astro image vs Picture: use <Image /> for nearly every local image. It resizes, converts to WebP, sets dimensions and lazy-loads. Use <Picture /> when you want several formats, typically AVIF with a WebP fallback, on large images where the extra savings matter. Use a plain <img> when something else already optimises the image (a CMS image CDN), for SVG icons, or for files in public/ you don’t want processed.
Key Takeaways
<Image />: one optimised format, responsivesrcset, no layout shift. The default choice.<Picture />: multiple formats via<source>elements. Best for heroes and large photos.- Plain
<img>: when optimisation happens elsewhere, or for SVG and tiny decorative assets.getImage(): when you need the URL rather than markup (CSS backgrounds, Open Graph).
Decision flow
- Is the image served by a CMS or image CDN that already resizes it? Yes → plain
<img>with the CDN’s parameters. - Is it an SVG? Yes → inline it, import it as a component, or use
<img>. Raster processing doesn’t help. - Do you need the URL, not an element? (CSS background, meta tag) →
getImage(). - Is it a large photo where AVIF savings matter? (hero, full-width banner) →
<Picture formats={['avif', 'webp']} />. - Otherwise →
<Image />.
Compared
<Image /> |
<Picture /> |
<img> |
|
|---|---|---|---|
| Output | <img> |
<picture> + <source>s + <img> |
As written |
| Formats | One (WebP default) | Several | Whatever the file is |
Responsive srcset |
With layout or widths |
With layout or widths |
Write it yourself |
| Dimensions set | Yes | Yes | Only if you add them |
| Lazy loading | Default | Default | Add loading="lazy" |
| Build cost | One encode per width | One per width per format | None |
Works with public/ files |
Needs dimensions; not optimised | Same | Yes |
Examples
---
import { Image, Picture } from 'astro:assets';
import hero from '../assets/hero.jpg';
import avatar from '../assets/avatar.jpg';
import logo from '../assets/logo.svg';
---
<!-- Hero: worth the extra AVIF encode -->
<Picture src={hero} formats={['avif', 'webp']} alt="Product dashboard" layout="full-width" priority />
<!-- Ordinary content image -->
<Image src={avatar} alt="Anika Rao" width={96} height={96} densities={[1, 2]} />
<!-- SVG logo -->
<img src={logo.src} width={logo.width} height={logo.height} alt="Acme" />
<!-- CMS image with its own CDN -->
<img src={`${cover.url}?w=1200&fm=webp`} width={1200} height={630} alt={cover.alt} loading="lazy" />
Things to know
- AVIF encoding is slower than WebP. On image-heavy sites,
<Picture />everywhere can noticeably lengthen builds; see faster Astro builds in CI. - Markdown images (
) are optimised like<Image />automatically. prioritygoes on one image per page: the LCP image.- Images in
public/aren’t processed by any of the three. Move them tosrc/to optimise them.
Every prop is listed in the image props cheatsheet, and sizing is explained in responsive images in Astro. For the performance impact, see the Astro performance guide. The official images guide covers every component.
FAQ
Is Picture always better than Image?
No. It produces more files and slower builds. Use it where the format savings are worth it, usually large images.
Can Image output AVIF?
Yes, with format="avif", but then browsers without AVIF support get nothing better. <Picture /> provides a fallback.