A product page can serve a small, modern image and still make visitors wait for it. The image might be discovered late, marked for lazy loading, hidden behind client-side data fetching or delayed by a busy rendering thread.
That is why reducing file size sometimes produces a disappointing Largest Contentful Paint result. Before changing compression settings again, trace when the browser learns about the image and when it can actually display it.
This guide covers React-rendered images and Next.js Image, with a workflow for deciding what to change and how to check the result. The examples assume the hero image is the likely LCP element for the layout being tested. Confirm that assumption on your own page: a heading or another image can become the LCP element at a different viewport.
Start with the element users are waiting for
Pick one important page and one representative device profile. Good candidates include a product detail page, a service landing page or an editorial article with a large cover image. Avoid starting with a site-wide component change before you understand one concrete failure.
Record a performance trace and identify the LCP element. For an image, compare the document request, the image request and the moment the image is painted. Google's LCP optimization guide separates the metric into server response time, resource discovery delay, resource loading duration and rendering delay.
Use that breakdown to choose an investigation:
What you observe | First thing to investigate |
|---|---|
The HTML itself arrives late | Server work, caching and upstream requests |
HTML arrives, but the image request starts much later | Client rendering, lazy loading and resource discovery |
The image request starts promptly but transfers slowly | Image dimensions, format, network and image delivery |
The image finishes downloading well before LCP | Visibility, rendering work, styles and application state |
A smaller image mainly addresses the transfer portion. It cannot recover time spent waiting for a client-side request that reveals the image URL several seconds into navigation.
Keep the original trace. You will need it to distinguish a real improvement from a faster network run or an already warm cache.
Give the hero a discoverable source
For a server-rendered React page, render the hero's source in the initial HTML whenever the application has enough information to do so. A placeholder followed by an effect that fetches the article and sets its image introduces additional work before the browser can request the asset.
Consider a CMS-backed article. The server already needs its title, slug and description. Fetching the cover metadata in the same server-side content request can make the complete opening section available together. Check the actual response HTML rather than assuming that using a server-rendering framework guarantees this behavior.
For a plain React image, a hero might look like this:
export function ArticleHero() {
return (
<img
src="/images/workshop-1280.webp"
srcSet={[
'/images/workshop-640.webp 640w',
'/images/workshop-1280.webp 1280w',
'/images/workshop-1920.webp 1920w',
].join(', ')}
sizes="(max-width: 1280px) 100vw, 1280px"
width={1920}
height={1080}
loading="eager"
fetchPriority="high"
className="article-hero"
alt="Two developers reviewing a prototype at a workshop"
/>
);
}
The example assumes a full-width image capped at 1280 CSS pixels, with proportional sizing supplied by the article-hero class. Supply the referenced image files and match the sizes value to your real layout. If the content has horizontal padding, account for it rather than copying the expression unchanged.
Width and height describe the image's intrinsic dimensions. They help the browser reserve the correct aspect ratio; responsive CSS still controls its displayed size. MDN's image element reference explains these attributes and the browser's responsive source selection.
Understand React's automatic image preloads
React can emit image preload hints during server rendering. That makes an ordinary img more capable than it may look in component code. The React img documentation describes exceptions, including images marked loading="lazy" or fetchPriority="low", images inside picture elements, and data URLs.
Inspect the generated HTML before adding manual preload tags. Check whether a hint already exists, which URL or responsive candidates it names, and whether the browser requests the same resource as the final image.
This is especially useful when a shared image wrapper supplies defaults. A wrapper designed for a long grid may set lazy loading everywhere. Reusing it for the page's lead image can produce a different loading policy from the one the page needs.
Give your component an explicit role or a documented loading policy. For example, a hero may be eager while a related-articles card remains lazy. Keep the decision visible at the page composition level so an editor adding another card does not accidentally promote it to a critical resource.
Do not infer network timing solely from a server-rendering test. Checking for preload markup verifies the framework's output. A browser trace is still needed to see how that output behaves alongside scripts, styles, fonts and other images.
Configure Next.js Image deliberately
Next.js Image generates image delivery URLs and responsive markup, but the page still needs an appropriate loading policy. Here is the same layout expressed with Image:
import Image from 'next/image';
export function ArticleHero() {
return (
<Image
src="/images/workshop.webp"
alt="Two developers reviewing a prototype at a workshop"
width={1920}
height={1080}
sizes="(max-width: 1280px) 100vw, 1280px"
loading="eager"
fetchPriority="high"
className="article-hero"
/>
);
}
In Next.js 16, priority is deprecated in favor of preload. The current documentation recommends loading="eager" or fetchPriority="high" for most cases and advises against combining preload with those properties. Use preload as a separate, deliberate choice when the page warrants it. See the Image API reference .
For responsive images, provide sizes. With fill, also give the parent a positioned layout and definite dimensions or an aspect ratio. These choices need to describe the actual space the image occupies. A card occupying one third of a desktop row should not declare that it spans the whole viewport.
Keep configuration changes local until verified. Altering the shared image component can affect dozens of page templates, including screens where the lead image is below the initial viewport or absent entirely.
Separate loading, priority and display size
These controls answer different questions. Loading determines whether fetching can be deferred. Fetch priority expresses a relative preference to the browser. Responsive sources let the browser choose an appropriate file for the displayed image and device.
Setting a high priority on every product card makes the application's intent unclear. Choose the resource that matters for the initial view and let ordinary images use ordinary scheduling. The browser remains responsible for the final scheduling decision; a priority hint is not a promise about exact request order. MDN documents that distinction in its fetchPriority reference .
For below-the-fold images, native lazy loading is a useful default. Browsers may fetch them before they become visible, so a request starting during the initial load does not by itself prove that lazy loading failed. Google's browser-level image lazy-loading guide explains the intended behavior.
Avoid using image loading flags to compensate for an inaccurate layout model. If a mobile design removes a large desktop illustration, check whether that illustration is still requested. If a carousel hides four slides, inspect whether its component eagerly loads all five. The appropriate fix may be in how the component selects and renders assets.
Check the bytes the browser actually selected
Open the network request for the image on a narrow viewport. Record the requested URL, transferred bytes and dimensions. Compare those with the element's displayed width and the device pixel ratio.
As a diagnostic example, a card displayed at 360 CSS pixels on a device with a pixel ratio of two needs roughly 720 image pixels for a one-to-one pixel mapping. The browser's choice can depend on other factors, but an enormous original should prompt a closer look at the available candidates and sizes declaration.
Do this for actual CMS content. A carefully compressed development placeholder tells you little about a 6000-pixel photograph uploaded by an editor. Test a photograph, an illustration and an image with fine text or product detail. Compression settings that look acceptable on one can damage another.
Set a practical editorial contract: source dimensions, accepted formats, focal point behavior and what happens when an image is missing. A stable contract reduces the chance that each new article reintroduces the same problem.
Also check the image service under both cold and warm conditions. Record cache state with the result. A fast cached response is useful evidence for repeat delivery, but it should not be presented as the cost of processing a new asset.
Measure a change without overstating the result
Make one change at a time on the chosen page. For example, remove lazy loading from the confirmed hero, then repeat the trace before changing image quality or layout.
Keep the viewport, network profile, device settings, page content and cache conditions consistent. Run several samples and retain the individual results. If the numbers vary widely, investigate the variation before claiming a small improvement.
A useful review record contains:
The page and the LCP element observed at the tested viewport.
The old and new loading markup.
Request start time, transfer size and LCP across repeated runs.
Screenshots showing that composition and image quality remain acceptable.
A separate check on a second viewport where the layout changes.
Lab measurements help explain a change. Field measurements show how the page behaves for real visitors. Keep those results separate and compare equivalent groups and periods. A release can improve one template while leaving the site's overall distribution largely unchanged.
If the image is downloaded early but painted late, stop compressing it and inspect rendering work. If server response dominates, investigate the server and content request path. The next action should follow the trace.
Make the fix survive the next article
Once the page behaves correctly, document the hero's loading policy in the component and content workflow. Add a representative page to your performance review routine. Include a check for missing dimensions, inaccurate responsive sizes and accidental lazy loading of the lead image.
For content-heavy websites, this work often crosses frontend code, CMS modeling and image delivery. Makers' Den's fast website development and growth engineering services can help identify the slow part of that path and verify changes against the pages that matter to your business.