Image sizes and priority

Match sizes to the rendered width; mark only the hero priority.

From next-best-practices, image.md and self-hosting.md.

Which file does each card get?

Drag the viewport and switch DPR.

fill, no sizesBad
slot–3 cards–
Good
slot–3 cards–
// 3 columns on desktop, 1 below 768px
<div className="relative aspect-[3/2]">
  <Image src="/card.png" alt="Card" fill sizes="(max-width: 768px) 100vw, 33vw" />
</div>

// Full-width hero
<Image src="/hero.png" alt="Hero" fill sizes="100vw" />

// Fixed avatar
<Image src="/avatar.png" alt="Avatar" width={200} height={200} sizes="200px" />

// next.config.js: fewer variants
module.exports = {
  images: { deviceSizes: [640, 750, 1080, 1920] },
}

When does the hero start?

Press Load page or drag the time.

<Image fill>Bad
LCP–
<Image fill priority>Good
LCP–
// Hero: preloaded
<Image src="/hero.png" alt="Hero" fill priority sizes="100vw" />

Priority on one image only

Scroll both feeds, then press Reload.

priority on allBad
load–hero–total–
priority on the heroGood
load–hero–total–
// Above the fold: the LCP image
<Image src="/hero.png" alt="Hero" fill priority sizes="100vw" />

// Below the fold: lazy by default
<Image src="/card.png" alt="Card" width={400} height={300} />

Why it matters, pros and cons

Why it matters

Without sizes the browser assumes 100vw. priority starts the hero at parse.

Pros

  • Grid cards download a fraction of the bytes.
  • LCP starts at HTML parse, not layout.
  • Below-fold images cost nothing until scrolled near.

Cons

  • sizes is hand-maintained; a grid change makes it lie.
  • priority on many images delays the real LCP.
  • Next.js 16 renames priority to preload.