An image CDN replaces the resize/encode/cache/serve pipeline you'd otherwise build yourself. One image source URL becomes thousands of variants on demand — resized for each viewport, encoded in the best format the browser supports, cached at edge nodes close to users. Performance wins are dramatic: 50-80% latency reduction, modern formats served automatically, dev time saved on build pipelines. This guide covers choosing a CDN, integration, and verification.
curl -sI -H "Accept: image/avif,image/webp,*/*" https://yoursite.com/hero.jpg # Look for: # Content-Type: image/jpeg → format not negotiated # Cache-Control: max-age=... → caching present # X-Cache: HIT/MISS → CDN presence # Server: cloudfront/cloudflare/etc → CDN identity
| Service | Pricing | Strengths | Notes |
|---|---|---|---|
| Cloudinary | $0 → $$$$ | Most features, AI cropping, video | Free tier 25 monthly credits |
| ImageKit | $0 → $$$ | Fast, simple URL API | Free tier 20GB delivery/month |
| Bunny CDN Optimizer | $ very cheap | Cheap, fast, simple | Pay-as-you-go from $0.01/GB |
| Imgix | $$$ | Enterprise, hundreds of params | Pro/enterprise focus |
| Cloudflare Images | $5/month + $$ | Bundled with Cloudflare account | 100k images storage, transforms |
| Vercel Image Optimisation | included with Vercel | Native Next.js integration | Locked to Vercel hosting |
For most small-to-mid sites, ImageKit or Bunny CDN offer the best price/performance. For sites already on Vercel/Netlify, use their built-in solution.
demo-cloud)https://res.cloudinary.com/<cloud_name>/image/upload/ <transformations>/ <public_id>.<format>
<!-- Original Cloudinary asset -->
<img src="https://res.cloudinary.com/demo/image/upload/sample.jpg" alt="...">
<!-- Resize to 800px wide -->
<img src="https://res.cloudinary.com/demo/image/upload/w_800/sample.jpg" alt="...">
<!-- Resize + auto format + auto quality -->
<img src="https://res.cloudinary.com/demo/image/upload/w_800,f_auto,q_auto/sample.jpg" alt="...">
<!-- f_auto: AVIF/WebP/JPEG based on browser
q_auto: optimal quality based on content
w_800: 800px wide -->
<!-- Full responsive set -->
<img src="https://res.cloudinary.com/demo/image/upload/w_800,f_auto,q_auto/sample.jpg"
srcset="https://res.cloudinary.com/demo/image/upload/w_400,f_auto,q_auto/sample.jpg 400w,
https://res.cloudinary.com/demo/image/upload/w_800,f_auto,q_auto/sample.jpg 800w,
https://res.cloudinary.com/demo/image/upload/w_1200,f_auto,q_auto/sample.jpg 1200w,
https://res.cloudinary.com/demo/image/upload/w_2400,f_auto,q_auto/sample.jpg 2400w"
sizes="(max-width: 800px) 100vw, 1200px"
width="1200" height="675"
alt="...">
<!-- Simple resize -->
<img src="https://ik.imagekit.io/yourkey/sample.jpg?tr=w-800,f-auto,q-auto" alt="...">
<!-- Or with helper SDK -->
import IKImage from 'imagekitio-react';
<IKImage
urlEndpoint="https://ik.imagekit.io/yourkey"
path="/sample.jpg"
transformation={[{ width: 800, format: 'auto', quality: 'auto' }]}
loading="lazy"
/>
Bunny is unique — works as a regular CDN that points at your origin, plus optional Image Optimizer add-on.
<!-- Bunny Optimizer URL parameters --> <img src="https://your-zone.b-cdn.net/hero.jpg?width=800&optimizer=image" alt="..."> <!-- With multiple params --> <img src="https://your-zone.b-cdn.net/hero.jpg?width=800&aspect_ratio=16:9&quality=80&optimizer=image" alt="...">
// next.config.js
module.exports = {
images: {
formats: ['image/avif', 'image/webp'],
remotePatterns: [
{ protocol: 'https', hostname: 'cdn.example.com' }
]
}
};
// Component
import Image from 'next/image';
<Image
src="https://cdn.example.com/hero.jpg"
alt="..."
width={1200}
height={675}
priority
/>
// Outputs srcset, sizes, format negotiation automatically
// Served via Vercel's image optimisation when hosted on Vercel
# Check cache HIT curl -sI https://res.cloudinary.com/yourcloud/image/upload/w_800,f_auto/hero.jpg | \ grep -i "x-cache\|cf-cache\|age\|cache-control" # Expected: # X-Cache: HIT # Age: 12345 (seconds since cached) # Cache-Control: public, max-age=31536000 # Check format negotiation curl -sI -H "Accept: image/avif" https://res.cloudinary.com/yourcloud/image/upload/f_auto/hero.jpg | \ grep -i "content-type" # Expected: Content-Type: image/avif curl -sI -H "Accept: image/webp" https://res.cloudinary.com/yourcloud/image/upload/f_auto/hero.jpg | \ grep -i "content-type" # Expected: Content-Type: image/webp
Verify CDN delivery is in place and measure latency improvement.
Run Image Audit →