Feature Image Workflow: Meta, Sizes and a Simple Call
Need this adapted for your organization? Work with AstroWeb.dev — Astro services by NViewsWEB.
Feature

Feature Image Workflow: Meta, Sizes and a Simple Call

How a hero image goes from one source file to responsive AVIF and WebP variants, with front matter meta, size tokens and a one-line component call.

A feature (hero) image has three jobs: look right at every screen width, load fast, and give search and social previews a proper picture. The workflow keeps each job in one place, so you drop in one file and set a few front matter fields.

1. Add the source file

Save one image in src/site/assets/images/. Images for avatars, profiles and featured art can also live in the avatar, profile and featured sub-folders; all folders are set in src/site/config/images.mjs.

  • Aim for 1200 x 630 px, PNG or WebP, under 200 KB, with no text baked into the picture (see docs/seo-image-checklist.md).
  • Use a descriptive file name. It becomes the image key and shows up in image search.

2. Build-time variants and meta

core/scripts/generate/images.mjs runs in the prebuild step of pnpm run dev and pnpm run build. It uses Sharp to:

  • write AVIF and WebP (plus the original format) files to public/images/YYYY/MM/, named <name>-w<width>-a<aspect>.<ext>,
  • pick the nearest aspect label (16x9, 1x1, 4x3, 2x1 and so on),
  • skip any width the source is too small for, so nothing is upscaled,
  • record the result in src/data/manifest/images.json: path, variants, formats, aspect and a content hash.

That manifest is the image “meta”. Layouts read it through getImageMeta() to get exact dimensions without opening the file at render time.

3. Size definitions

Sizes are tokens in src/site/config/images.mjs, not numbers scattered through components.

Setting Default Meaning
imageVariants 380, 640, 1280 Widths generated for every image
variants.mobile / tablet / desktop / full 380 / 640 / 640 / 1280 Which width each screen class asks for
variants.featured 960 Width used for the featured slot
variants.thumbnail / avatar 120 / 60 Small card and author sizes
breakpoints 460 / 1079 / 1080 / 1440 Mobile max, tablet max, desktop and full minimums
imageFormats, legacyImageFormats avif, webp Formats for R2 sync and for local images
compressionLevel 80 Quality for generated files

The site defaults for pages without their own image are image, featuredImage and thumbnailImage, each with Alt and Title companions.

4. Front matter

heroImage: "my-feature-image.png"
heroImageAlt: "What the picture shows, in one sentence"
heroImageTitle: "Optional title"
heroImageCaption: "Optional caption"

Entries without heroImage fall back to the site default, which is why every page should set its own: a shared image makes every social preview look identical.

5. The simple call

The post layout already renders the hero for you, with loading="eager" so the largest image is preloaded and does not lazy-load. In your own markup the call is one line:

---
import ResponsiveImage from 'core/components/ResponsiveImage.astro';
---
<ResponsiveImage src="my-feature-image.png" alt="Describe the image" sizes="(max-width: 768px) 100vw, 960px" />

ResponsiveImage looks up the meta, builds srcset and sizes, sets an a-<aspect> class so the box keeps its shape (no layout shift), and registers the image for JSON-LD. Useful props: variant (auto, thumbnail, desktop, featured), loading (lazy or eager), width, objectFit and addSchema. For a plain file with no variants use SimpleImage, which takes src, alt, width, height, loading and fetchPriority.

Eager images are collected in a preload registry and printed once as <link rel="preload" as="image"> by ImagePreload.astro, so you do not add preload tags by hand.

6. Larger media: R2

Public files can also be served from Cloudflare R2. Use a media: key as src (or the mediaKey prop) and ResponsiveImage resolves the stored variants and alt text through resolveMedia. See Images: Local Variants, Public Files and R2.

Checklist

  1. One source file in src/site/assets/images/.
  2. Run pnpm run dev or pnpm run build so the variants and images.json are regenerated.
  3. Set heroImage, heroImageAlt and heroImageTitle in front matter.
  4. Check the page source: one preload for the hero, a srcset, width and height present.