Next.js Image Optimization: From Slow LCP to Sub-Second Load
By Arash Latifi
Practical guide to Next.js image optimization with next/image, modern formats, correct sizes, and smart caching to fix LCP and Core Web Vitals.
TL;DR: Most Next.js slowness comes from images, not code. With correct
next/imageusage, precisesizes,AVIF/WebP, and proper caching, you can cutLCPfrom 3s to under 1.5s without losing quality.
Why images are the bottleneck
A 2500px hero as old JPEG easily hits 800KB. On mobile, that single file ruins LCP. next/image gives you automatic resizing, modern formats, and lazy-loading, but if sizes and priority are wrong, the browser still downloads the largest variant. Optimization means telling the browser exactly what size you need.
If your whole site feels slow, start with the speed and Core Web Vitals guide; here we go deep only on images.
Correct next/image setup
Three simple rules:
1. Provide real dimensions. Use true width and height so CLS stays at zero.
2. Write exact sizes. The default 100vw makes the browser fetch the biggest file.
3. Prioritize only the LCP image. Everything else should stay lazy.
| Pattern | What it does | When to use |
| --- | --- | --- |
| priority + fetchPriority="high" | Fast hero load | Only one above-the-fold image |
| sizes="(max-width: 768px) 100vw, 50vw" | Correct size hint | Two-column cards |
| placeholder="blur" | Prevent layout shift | Product lists |
For a product card that is 50% width on desktop, a wrong sizes can triple the bytes.
Modern formats and smart sizing
Enable modern formats in next.config.js. AVIF is smallest, WebP has wider support. Next.js picks the best automatically.
Tip: some Iranian hosts don't cache AVIF well. Check Cache-Control headers and, without a CDN, at least configure remotePatterns correctly so resizing happens at the origin. For supplier remote images, restrict remotePatterns to the main domain.
If you recently migrated to Tailwind v4, make sure content includes image paths so aspect-ratio classes aren't purged.
Caching, CDN, and lazy loading
Optimized images without caching don't help. Check three layers:
- Browser: Next.js sets
Cache-Control: public, max-age=31536000, immutablefor optimized images by default. - CDN: If you use Cloudflare or Arvan, enable tiered cache to avoid repeated resizes.
- Page structure: Keep below-the-fold images
loading="lazy"and never setpriorityeverywhere — that common mistake hurtsLCP.
For debugging, test the Network tab without Disable cache and check Content-Type to see if avif is actually returned. If you still see jpeg, formats isn't active or the browser's Accept header is old.
For heavy hydration after images, see form validation with Zod to avoid pushing LCP back.
Optimization checklist
- [ ] Only one hero image has
priority, rest arelazy - [ ] Every
Imagehas realwidth/heightand precisesizes - [ ]
formats: ["image/avif", "image/webp"]enabled innext.config.js - [ ]
placeholder="blur"for cards and product lists - [ ]
remotePatternslimited to needed domains only - [ ] CDN cache and
Cache-Controlfor/_next/imageverified - [ ] Mobile Lighthouse:
LCPunder 2.5s andCLSunder 0.1
FAQ
Should I convert everything to AVIF manually?
No. Let Next.js choose. Just enable formats and keep quality at 75-85. Manual conversion often degrades quality.
Why is LCP still high with next/image?
Three common causes: priority on the wrong image, sizes="100vw" for a small card, or a hero built with CSS background-image instead of Image. Build the hero with Image and priority.
Supplier remote images are slow — what to do?
Restrict remotePatterns, reduce deviceSizes, and locally host bestsellers if possible. Remote resizing hits the origin every time, and a slow supplier server keeps TTFB high.