How to Fix LCP on Image-Heavy Pages (Next.js Patterns That Work)
Apr 24, 2026 · 4 min read
If your page is image-heavy (portfolio, case studies, blogs with hero media), LCP is almost always dominated by one thing:
- a hero image,
- a gallery grid above the fold,
- or an image carousel that loads too much too early.
This post is the exact workflow I use to get LCP < 2.5s reliably on real devices — not just in Lighthouse.
Step 0: Don’t guess — find the true LCP element
Before you change anything, identify what’s actually being reported as LCP.
Where to check
- Chrome DevTools → Performance: record load and look for “Largest Contentful Paint”.
- Lighthouse: use it to get hints, but verify in DevTools.
- Field data: Search Console Core Web Vitals groups by URL pattern; it tells you where to focus.
If the LCP element is a heading, your issues are often fonts, CSS, or hydration.
If the LCP element is an image, your issues are usually bytes + priority + caching.
The main LCP killers on image-heavy pages
In practice, LCP gets worse because of:
- Slow TTFB (server work, no caching, cold starts)
- Too many bytes (oversized hero images, unoptimised formats)
- Bad loading order (the hero image isn’t requested early)
- Render-blocking work (fonts, CSS, heavy JS before paint)
You fix LCP by addressing these in order.
1) Reduce TTFB (because LCP can’t start without HTML)
Even perfect images won’t help if the server responds slowly.
Patterns that work
- Cache full pages where possible (edge/CDN)
- Avoid per-request expensive work on marketing pages (DB calls, heavy Markdown parsing)
- Use static generation for content pages
- Move non-critical work to after render (analytics, tracking, personalization)
Quick sanity check
If TTFB is > 800ms for most users, fix that first.
2) Ship the right image bytes (format + dimensions)
Most LCP wins come from sending fewer bytes earlier.
Rules I follow
- Never serve a 2500px image to a 390px viewport.
- Prefer AVIF/WebP when available.
- Keep the LCP image as small as possible without looking soft.
Practical targets
- Hero image often can be 100–250 KB (sometimes less) and still look great.
- Avoid huge PNGs for photos (they’re almost always wrong).
3) Make the LCP request happen immediately
If the browser doesn’t request the hero image early, LCP will suffer even if the image is small.
Next.js patterns that work
- Use
next/imagefor responsive sizing and modern formats. - For the hero image, set priority so it’s fetched early.
- Ensure the LCP image is not hidden behind a lazy-loaded carousel or a conditional render.
Common mistake
“Lazy-loading everything” feels like the right move but can backfire: the hero should be eager.
4) Use sizes correctly (this is where most teams fail)
If you don’t set sizes, the browser might choose a larger srcset candidate than needed.
The goal is simple: tell the browser the rendered width at each breakpoint.
Example thinking (not copy/paste):
If your hero is full-width on mobile, but constrained to 720px on desktop, sizes should reflect that.
5) Preload what matters (but don’t preload everything)
Preloading is powerful when used for the one resource that blocks LCP.
Good preload candidates:
- the hero image (if it’s LCP)
- the critical font file (if heading/text is LCP)
Bad preload candidates:
- multiple gallery images
- below-the-fold media
6) Avoid above-the-fold image “work”
Some patterns look nice but destroy LCP:
- blur + heavy filters
- client-side parallax effects on the hero
- large background images applied via CSS that aren’t optimised
If you want motion, apply it after first paint.
7) Reduce JS before paint (especially client components)
On image-heavy pages, you often still lose LCP because the main thread is busy:
- large client bundles,
- third-party scripts,
- hydration costs.
What I do
- Keep the hero and initial layout server-rendered.
- Move interactive widgets below the fold or load them after interaction.
- Audit third-party scripts (most are a tax).
A repeatable debugging workflow (use this every time)
- Identify the true LCP element.
- Check TTFB and caching.
- Check image bytes and format.
- Ensure the hero request is early (priority/order).
- Fix
sizesso the browser chooses the right candidate. - Reduce JS/third-party blocking.
- Validate in field data.
Quick checklist for image-heavy pages
- LCP element is known (image vs text)
- HTML response is cached
- Hero image is compressed + correct dimensions
- Hero image is requested early (priority)
sizesis accurate- No render-blocking surprises (fonts/JS)
- Third-party scripts deferred
Related posts
All posts →INP for React Apps: Profiling and Eliminating Long Tasks
Apr 25, 2026 · 4 min read
INP is responsiveness. Learn how to find long tasks, profile React re-renders, reduce main-thread work, and ship fast interactions consistently.
Why Core Web Vitals Matter (and How I Improve Them)
Apr 22, 2026 · 5 min read
Core Web Vitals affect rankings, conversions, and perceived quality. Here’s what each metric means, target thresholds, how to measure, and the fixes that move the needle.
Why I Use Next.js + Sanity for Content Sites
Apr 20, 2026 · 4 min read
A practical breakdown of when Next.js + Sanity is the right stack, what it buys you for SEO and velocity, and the trade-offs to watch.