Using images
Astro has inbuilt image handling components and utilities. Find here the different approaches and best practice recommendation for the most common use cases.
Images can be stored in /src or /static – Images in /src are transformed
by astro (resized, optimized etc.) and the files in /static are kept as they
are. Thus in general, images should always go in /src because we want them
to be optimized. Things like favicons can go into /static.
Static images
Static images are referenced through their absolute paths and astro has no
knowledge of their content only of their location. So given the image
/static/example.png you can reference /example.png and the exact same file
will be rendered.
Astro assets (Astro transformed images)
The default location for assets is /src/assets and there is an import alias
@assets to that location. However images can also be co-located with their
importing files (or some other place within /src).
When astro loads the images they are
turned into ImageMetadata which is an object containing things like mime
type, size etc. With this object astro can created multiple derivative files
(“transform”) such as different file types, sizes.
Loading assets
Astro can be told to load images in multiple ways:
-
✅ Importing an image in an astro component:
--- import { Image } from "astro:assets"; // @assets is an alias for /src/assets import img1 from "@assets/img1.png"; --- <Image src={img1} alt=""> -
✅ Using the
imagehelper function in the content collection schema definition: This means an image file referenced in frontmatter are transformed intoImageMetadatain the loaded collection entry. -
Using glob-based loading with
import.meta.glob(This was used in one project and unfortunately it has propagated into loads of projects which don’t actually need it) – This is the most complex and powerful mechanism which should only be used when absolutely necessary:You can find it in some project’s
src/lib/images.tswithin theloadImagefunction. This function loads all images with a certain glob and returns the image which fits a certain string match passed through a function parameter. This works well for situations where there are a diverse set of images in different locations which need to be referenced all over the place. However, this means that there is an extra level of abstraction between the intention (“Calling the function with a string parameter with the name of a file”) and the implementation of that intention (“Saving a file with a certain name”).This means there is no way to statically analyze the image reference and therefore for the compiler/IDE to flag errors or provide autocomplete. If there is a typo or some other problem then this is not technically an error and can go unnoticed. Another downside to this approach is that it is not possible to determine if there are unused files within the repository and delete them or indeed exclude them from the build artifact. With this approach all images are always in use.
For this reason this approach should only be used within defined borders.
Using assets within templates
Once loaded an image (resolved to ImageMetadata) can used in multiple
ways:
-
✅
<Image />component from astro (imported asimport { Image } from "astro:assets";) for 99% of use cases, can provide different sizes and and accepts all attributes an<img>element accepts. This component automatically sets the width and height of the resulting<img>tag which prevents layout shift when the image is loaded. Also passing awidthsproperty automatically generates image files with those widths and puts them into asrcsetattribute. Manually setting thesizesattribute of the element by analyzing the responsive size of that element within the layout results in optimized responsive image sizes. (These can be manually calculated, or you can use the Responsive Image Linter extension) -
<Picture />component from astro (imported asimport { Picture } from "astro:assets";). Is basically like<Image />but also supports generating different formats of image files. Use this if you don’t have any control over the input formats. – But this is probably rarely required. -
getImage()function for situtions where programmatic image transformation is required (for example: youtube preview images, opengraph thumbnails etc.) – for most content-related use cases this is not required.
An example of an astro page with an image:
---
import img1 from "@assets/img1.png";
---
<Layout>
<div class="row">
<div class="col-xs-7 col-md-3">
<Image src={img1} widths={[500, 1000, 1500]} sizes="(max-width: 900px) 90vw, (max-width:1100px) 70vw, 40vw">
</div>
</div>
</Lyout>
Using assets in MDX content
ℹ️ For frontmatter image references, use the image schema helper and render that with the
<Image />component.
There are two possible solutions to loading optimized images from within markdown body content:
-
✅ Using a top-of-file import and the
<Image />component:--- title: Lorem Ipsum --- import { Image } from "astro:assets"; import img1 from "@assets/img1.png"; <Image src={img1} > -
✅ For use cases where the client is working with the content files (which is probably the case, because why else would you use mdx and not
.astrofiles?) – You can do the following:In the MDX file, load the image with standard markdown syntax:
Then when it comes to rendering the markdown content, customize the component used to render the image and set the
widthsandsizesattributes for optimized responsive images:--- // An astro component rendering markdown content // such as /pages/features/[id].astro import { FeatureImage } from "@components/FeatureImage.astro"; // ... const { entry } = Astro.props; const { Content } = await render(entry); --- <Content components={{ img: FeatureImage }} />And the
FeatureImage.astrolooks like this:--- import { Image } from 'astro:assets'; import type { ImageMetadata } from 'astro'; type Props = { // src can also be string when the path was an absolute // path, a remote URL or when the image was actually written // as plan html <img> not with the markdown syntax. src: string | ImageMetadata; alt: string; }; const { src, alt } = Astro.props; --- { typeof src === 'string' ? ( <img src={src} alt={alt} /> ) : ( <Image {src} {alt} widths={[500, 1000, 1500]} sizes="(max-width: 900px) 90vw, (max-width:1100px) 70vw, 40vw" /> ) }