Lesson 21 of 81
Images are usually the single heaviest thing on a page, and also the easiest performance win to get wrong twice — once by ignoring optimization entirely, and once by marking every image 'urgent' until none of them actually are. next/image automates the first problem and makes the second one obvious once you know what to look for.
11 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
A developer marks every image on a long product listing page with `preload` because they read that it speeds up loading. What's wrong with this approach?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
next/image's <Image> component extends the plain HTML <img> with automatic optimization: it resizes the source image to whatever size the browser actually needs, converts it to a modern format like WebP when the browser supports one, and lazy-loads by default — an image below the fold doesn't download until the browser is about to need it. None of this requires configuration to get for free; it's the baseline behavior of just using <Image> instead of <img>.
Two props exist specifically to correct the defaults when they're wrong for a given image:
sizes — tells the browser how wide the image will actually be rendered at different viewport widths, so it can pick the right size out of the generated srcset instead of guessing. Without sizes, the browser assumes the image will be as wide as the full viewport (100vw), which can mean downloading a needlessly large file for an image that's actually rendered at a third of that width.preload — hints the browser to start loading this specific image immediately, inserted as a <link> in <head> before it's even discovered in the body. This is the correct tool for a page's Largest Contentful Paint (LCP) image — usually a hero image above the fold — because that's the one image whose load time the browser's paint metric is actually waiting on. (This prop replaces priority, which is deprecated as of Next.js 16 — code written against an older version's tutorials will still say priority={true}.)// app/page.tsx
import Image from "next/image";
export default function HomePage() {
return (
<>
<Image
src="/hero.jpg"
alt="Praxis dashboard showing today's spaced-repetition queue"
width={1600}
height={900}
preload
sizes="100vw"
/>
<div className="grid grid-cols-3 gap-4">
{cards.map((card) => (
<Image
key={card.id}
src={card.thumbnail}
alt={card.title}
width={400}
height={225}
sizes="(max-width: 768px) 100vw, 33vw"
/>
))}
</div>
</>
);
}
Only the hero gets preload — it's the image the LCP measurement is almost certainly waiting on, so paying to start its download early is a real win. The card grid images deliberately don't get it: they're below the fold, lazy-loading is the right behavior for them, and marking a dozen images "urgent" defeats the entire point of prioritization — the browser can't actually fast-track everything at once, so preload on every image is functionally the same as preload on none of them, just slower.
priority is deprecated as of Next.js 16 — the current prop is preload. They mean roughly the same thing, but code, docs, or interview answers built from older training data will say priority={true}; know that the concept survived the rename even if the exact prop name didn't.preload on every image defeats its purpose. The browser only has so much bandwidth to front-load; preload is for the one (or very few) images the LCP metric is actually waiting on, not a general "make this faster" switch.sizes, the browser assumes full-viewport width and downloads accordingly — an image that's actually rendered at a third of the screen's width still pulls a full-viewport-sized file unless sizes tells the browser otherwise.remotePatterns, not domains, is the current way to allow-list external image hosts. domains has been deprecated since Next.js 14 specifically because it can't scope by protocol, port, or path the way remotePatterns can — a bare hostname allow-list is much easier to abuse.width/height set the aspect ratio Next.js uses to reserve layout space, not the rendered display size. The actual on-page size is controlled by CSS; skip them only when using the fill prop or a statically imported image, where Next.js can infer them itself."Your homepage's Lighthouse LCP score is worse than expected — walk me through how you'd investigate the hero image" is a real, common performance question, and a candidate who reaches for preload on the hero (and explains why it shouldn't go on the images below it) is demonstrating an actual mental model of prioritization, not just "add optimization props until the score goes up."