Serve Optimized Images: Compress Without Losing Quality
Unoptimized images are the #1 cause of page bloat. Learn how to compress, convert, and serve images efficiently to slash load times.
Images typically account for 50-75% of a page's total weight. Serving unoptimized images is the single easiest performance win you're probably leaving on the table.
Why Image Optimization Matters
- Largest contributor to page weight — average page serves 1-5MB of images
- Directly impacts LCP — hero images are often the LCP element
- Easy wins — compressing images can cut 50-80% off file sizes with no visible quality loss
Audit: "Efficiently encode images"
Lighthouse flags images that could be smaller without visible quality loss. It re-encodes each image at quality 85 and compares — if savings exceed 4KB, it flags it.
How to Fix
1. Convert to WebP or AVIF
Modern formats compress dramatically better:
| Format | Compression vs JPEG | Browser Support |
|---|---|---|
| WebP | 25-35% smaller | 97%+ |
| AVIF | 40-50% smaller | 93%+ |
| JPEG XL | 35-45% smaller | Limited (Chrome flag) |
Using the <picture> element for fallbacks:
<picture>
<source srcset="/images/hero.avif" type="image/avif">
<source srcset="/images/hero.webp" type="image/webp">
<img src="/images/hero.jpg" alt="Hero image" width="1200" height="600">
</picture>
2. Compress Images at Build Time
Use Sharp (Node.js) to batch-convert images:
import sharp from "sharp";
await sharp("input.jpg")
.resize(1200) // resize to max width
.webp({ quality: 80 }) // convert to WebP
.toFile("output.webp");
Or use the Squoosh CLI:
npx @squoosh/cli --webp '{"quality": 80}' --resize '{"width": 1200}' *.jpg
3. Use an Image CDN
Image CDNs automatically serve the best format for each browser:
<!-- Cloudinary: auto-format and auto-quality -->
<img src="https://res.cloudinary.com/demo/image/upload/f_auto,q_auto/hero.jpg"
alt="Hero" width="1200" height="600">
<!-- Imgix: similar auto-optimization -->
<img src="https://example.imgix.net/hero.jpg?auto=format,compress&w=1200"
alt="Hero" width="1200" height="600">
4. Next.js Image Component
Next.js optimizes images automatically:
import Image from "next/image";
<Image
src="/images/hero.jpg"
alt="Hero"
width={1200}
height={600}
quality={80}
priority // for above-the-fold images
/>
This automatically serves WebP, resizes, and lazy loads.
5. Set Correct Quality Levels
Don't use quality 100 — the file size balloons with minimal visual difference:
| Quality | File Size | Visual Difference |
|---|---|---|
| 100 | 500KB | Reference |
| 85 | 150KB | Imperceptible |
| 75 | 100KB | Barely noticeable |
| 60 | 70KB | Slight softening |
Quality 75-85 is the sweet spot for most images.
Quick Wins Checklist
- Convert all images to WebP (AVIF if you don't need legacy support)
- Set quality to 75-85 for photos, 85-90 for text-heavy images
- Use
<picture>with format fallbacks - Set explicit
widthandheighton all<img>tags - Use an image CDN or Next.js Image for automatic optimization
- Audit with
npx lighthouseand check "Efficiently encode images"
Ready to stop wasting ad spend?
Track your landing page performance, monitor Core Web Vitals, and calculate exactly how much slow pages cost you.
Start Free — No Credit Card