Images are still one of the easiest ways to wreck Largest Contentful Paint.
You can have a clean React app, a tidy component tree and a decent bundle size, then lose the whole page to one 2400px hero image that loads lazily from a slow origin. I have seen that exact problem more times than I would like.
The annoying part is that "use an image CDN" is not always the answer. Sometimes next/image is enough. Sometimes a CDN is exactly what you need. Sometimes the real fix is boring: set the right sizes, stop lazy-loading the hero image, and stop letting CMS uploads go live without constraints.
This guide is for choosing the right image optimization setup without buying more tooling than the site needs.
Start with the actual image problem
Do this before choosing a tool. Work out which problem is hurting the page:
- Files are too large.
- Mobile users get desktop-sized images.
- JPEG or PNG is being used where WebP or AVIF would be smaller.
- The browser discovers the hero image too late.
- The LCP image is lazy-loaded or not prioritised.
- Images are transformed repeatedly instead of cached.
- Editors can upload anything and the frontend has no guardrails.
Compression tools help with file size. Image CDNs help with sizing, formats, caching and transformations. Framework image components help with responsive markup and layout stability.
None of them fix a hero image that only appears after client-side JavaScript runs.
Quick picks
- Next.js on Vercel or a compatible host: start with
next/image. - React SPA or Vite site: use build-time optimization for local images or an image CDN for CMS assets.
- Astro/content site: use Astro's image tooling for local files and a CDN for media libraries.
- WordPress: use a plugin/CDN workflow, but check the LCP image after enabling it.
- Agency/client sites: pick the option that prevents non-developers from accidentally uploading a 4 MB homepage banner.
Next.js Image component
Next.js already has a good image story through the Image component. It can create responsive variants, lazy-load non-critical images and reserve space to reduce layout shift.
Use it first when:
- the site is already on Next.js
- images are local or come from known remote domains
- your host supports the optimization flow you need
- you do not need a shared media library across several sites
Example:
import Image from 'next/image';
export function Hero() {
return (
<Image
src="/hero-dashboard.jpg"
alt="Dashboard preview"
width={1200}
height={700}
priority
sizes="(max-width: 768px) 100vw, 1200px"
/>
);
}
The small details matter:
- Use
priorityfor the real LCP hero image. - Add an accurate
sizesvalue. The default can be too broad for real layouts. - Do not hide critical images behind components that only render after client state loads.
- Configure
remotePatternsproperly for CMS images.
Where it gets awkward:
- complex editorial cropping
- lots of remote CMS media
- transformations shared across multiple products
- art direction, overlays or reusable image presets
- non-Next.js sites in the same business
If the image workflow is bigger than one Next.js app, reach for a CDN.
Cloudinary
Cloudinary is the heavyweight option. It handles image and video storage, transformations, responsive delivery, cropping, overlays and asset management.
It makes sense when media is part of the product workflow, not just a folder of static images.
Use Cloudinary when:
- editors upload a lot of media
- you need transformations, crops, overlays or art direction
- multiple sites share the same assets
- you need image and video handling together
- non-developers need a media UI
Example URL pattern:
<img
src="https://res.cloudinary.com/demo/image/upload/f_auto,q_auto,w_800/sample.jpg"
width="800"
height="533"
alt="Optimized sample"
/>
f_auto lets Cloudinary choose the format. q_auto handles quality. The width parameter stops you sending the original monster file to every device.
Watch the usual trade-offs: pricing, transformation sprawl, account limits and keeping image presets consistent across the team.
ImageKit
ImageKit is a focused image CDN with URL-based transformations, automatic format conversion, quality settings and media management.
It is a good fit when you want image delivery improvements without building your own pipeline.
Use ImageKit when:
- images come from a CMS, S3 bucket or existing origin
- you want global delivery and transformations
- you want to keep existing asset URLs mostly intact
- you need a lighter image platform than Cloudinary
Typical URL pattern:
<img
src="https://ik.imagekit.io/example/site/hero.jpg?tr=w-800,q-80,f-auto"
width="800"
height="533"
alt="Optimized hero"
/>
The main thing to check is whether your generated widths match the sizes values in your frontend. A CDN can generate perfect variants and still waste bandwidth if the HTML asks for the wrong one.
Imgix
Imgix is a developer-friendly image CDN built around URL parameters and precise transformations. It is useful when the engineering team wants control and the source images already live somewhere else.
Use Imgix when:
- images live in S3, a CMS or another origin
- you need cropping, DPR variants and format control
- engineers are comfortable managing transformation URLs
- you want a mature CDN workflow without a full DAM-style setup
The risk is complexity leaking into templates. If every component invents its own transformation string, the site becomes harder to maintain. Create presets or helper functions early.
Cloudflare Images, Image Resizing and Polish
Cloudflare has a few image options, depending on your plan and setup. Cloudflare Images can store and transform images. Image Resizing can transform assets at the edge. Polish can optimize images that pass through Cloudflare on supported plans.
Use Cloudflare when:
- the site already sits behind Cloudflare
- you want fewer vendors
- your image needs are fairly straightforward
- edge delivery matters more than media-library features
Check plan availability before designing around a feature. Also check cache behaviour carefully, especially when images are replaced but URLs stay the same.
ShortPixel, TinyPNG and build-time compression
Not every site needs an image CDN.
For small static sites, build-time compression may be the sanest option. Run images through Sharp, Squoosh, ShortPixel, TinyPNG or a similar tool before deploy. Commit the optimized files. Move on.
That works well when:
- there are not many images
- images live in the repo
- content changes slowly
- editors are not uploading new media every day
- transformations on demand would be overkill
A simple Sharp script that creates WebP/AVIF variants and resizes large originals can beat a paid CDN for a small developer-owned site.
The LCP image checklist
Before blaming your image service, check the page itself:
- Is the LCP image the right size for mobile?
- Is it present in the initial HTML?
- Is it prioritised with
priority,preloadorfetchpriority="high"where appropriate? - Is it accidentally lazy-loaded?
- Are
widthandheightset? - Is it a CSS background image that the browser discovers late?
- Is TTFB slow before the image even starts loading?
- Are third-party scripts or heavy JavaScript delaying render?
Most bad LCP images fail more than one of those checks.
Example hero image markup
For a non-Next.js site:
<link
rel="preload"
as="image"
href="/images/hero-1200.webp"
imagesrcset="/images/hero-600.webp 600w, /images/hero-1200.webp 1200w"
imagesizes="100vw"
/>
<img
src="/images/hero-1200.webp"
srcset="/images/hero-600.webp 600w, /images/hero-1200.webp 1200w"
sizes="100vw"
width="1200"
height="700"
fetchpriority="high"
decoding="async"
alt="Product dashboard showing performance metrics"
/>
Preload one image carefully. Do not preload every image above the fold and hope for the best. Preload the actual LCP candidate, then check the waterfall.
Which option should you choose?
Choose framework-native optimization when the stack already supports it, image sources are simple and you do not need cross-site media management.
Choose an image CDN when images come from a CMS, multiple sites share assets, non-technical users upload media, or image traffic is commercially important.
Choose build-time compression when images live in the repo and content changes slowly. It is boring, cheap and often enough.
Related PageSpeedFix guides
Bottom line
For many Next.js sites, next/image is the right first move. For CMS-heavy sites, agencies and ecommerce, an image CDN is usually worth it. For small static sites, a build-time script may be all you need.
Do not buy a tool before fixing loading priority, responsive sizes and LCP discovery. Those mistakes can wipe out most of the benefit.
