Image Optimization
Image optimization is delivering each image in the fewest bytes that still look right: re-encoding to a modern format such as WebP or AVIF, resizing to the size the page displays, tuning encoder quality, and stripping metadata. A CDN keeps one master and derives a cached copy per request.
Full Explanation
Image optimization is the practice of delivering every image in the fewest bytes that still look right to the viewer. Four things can be done to the file: re-encoding it into a more efficient format, resizing it to the dimensions the page actually renders, tuning the encoder's quality setting, and stripping metadata the viewer never sees. On a CDN the work happens at the edge. The origin stores one high-quality master. A derived copy is generated per request and cached. As a result, the encode runs once per variant rather than once per visitor.
It is not image editing. It never modifies the master. Every step affects only the delivered copy. Nor is it one format or one technique. Only the format and quality steps are true compression. Resizing and metadata stripping simply remove bytes the client had no use for. Vendors sell the capability under the name transformations. The format actually delivered is usually chosen per request by content negotiation, rather than fixed in the markup.
How it works
An image-optimizing CDN keeps one high-quality master per image and derives a copy for each distinct set of options. The options come from the request URL, from what the browser says it can decode, or from both. The encoded result is stored in the edge cache. So a repeat request for the same variant is served without re-encoding.
A derived copy combines some or all of four transformations:
- Format conversion. Re-encode into a codec that compresses better than JPEG or PNG at the same visual quality, normally WebP or AVIF. imgix documents WebP lossy images as 25 to 34% smaller than JPEG. It documents AVIF as up to 50% lighter than JPEG and up to 30% lighter than WebP. web.dev cites tests showing greater than 50% savings against JPEG for AVIF in some cases. Both formats also do lossless.
- Resizing. Scale to the size the page displays. As a result, a phone does not download a desktop-sized file. Cloudflare's guidance is that image sizes should match the exact size that they are displayed on the page. Where sizes must be hardcoded, it recommends maximums of 1920 pixels for desktop browsers, 960 for tablets and 640 for mobile phones. In markup, the srcset and sizes attributes let the browser choose. The HTML Standard notes that with w descriptors and sizes, the user agent can choose the correct image source to download regardless of how large the user's device is.
- Quality tuning. Lower the encoder's quality setting until the byte saving stops being worth the visible loss. There is no universal value. web.dev states that when compressing, there isn't a universal setting suitable for all cases. Its recommended approach is to experiment with different compression levels until you find a good compromise between image quality and file size.
- Metadata stripping. Discard the EXIF, ICC and vendor blocks that cameras and graphics tools embed. Cloudinary's rule is to keep the metadata in your original copy of the graphics, but remove it in delivered images.
Format selection is the step that involves the client. The browser advertises the image types it can decode in the Accept request header. The pipeline reads that header and picks the best format the client accepts. It normally picks AVIF first, then WebP, then the source format. imgix documents exactly that chain for auto=format. If the browser does not support AVIF, it will first fallback to WebP if it is supported. If WebP is unsupported, it falls back to the source image type. Cloudflare's format=auto behaves the same way. Its Worker example branches on image/avif and image/webp in the Accept header. Expressed in pure markup, the picture element encodes the same order. In web.dev's example, the AVIF format takes priority over the WebP format, falling back to the JPEG format if neither AVIF or WebP is supported.
Because one URL can then return different bytes to different clients, the cache must key on the client's format preference. It must also key on the URL. That is what the Vary response header is for. Cloudflare's Vary for Images works by parsing the Accept header in each request to determine which image format the browser supports, then serving the matching cached variant. It also caches each variant separately. Where the format is instead selected by URL parameters, each parameter combination is simply its own cache key. No negotiation is involved.
Why it matters for a CDN
Images are the biggest single lever on page weight. web.dev describes images as often the heaviest and most prevalent resource on the web. The 2024 Web Almanac measures the median desktop homepage loading 1,054 KB of images against 613 KB of JavaScript. It measures the median mobile homepage loading 900 KB of images. At the 75th percentile, it is 2,822 KB of images on desktop and 2,517 KB on mobile. The Almanac adds a qualification worth keeping. Images have always been the largest contributor to page weight overall. But its 2024 inner-page data shows that's a trend specific to homepages, where images remain the predominant resource type excluding video.
Image bytes are therefore where a CDN wins most of its byte reduction. The win lands on the path the user waits on. A smaller file spends less time on the wire. This lowers the latency before the image appears. web.dev states the metric link directly. Serving images in modern formats reduces a resource's load time, which may result in a lower Largest Contentful Paint (LCP). A good LCP score is 2.5 seconds or less. Note the may. The format change moves LCP only when the image is the LCP element and its transfer was the slow part.
Running the transformation at the edge rather than at the origin also economizes origin traffic. Cloudflare notes that requests for multiple different image sizes are likely to reuse the cached original image without causing extra transfers from the origin server. So a single origin fetch backs a whole family of variants.
What CDNs do
- Cloudflare: Cloudflare Images enables developers to optimize images at scale by dynamically generating different versions in real time. This is driven either by URL options or by the Images binding in a Worker. For images not stored in Cloudflare Images, the documented transformation URL is a zone hostname plus the fixed prefix /cdn-cgi/image/. It then has a comma-separated option list, then the source image. Images hosted in Cloudflare Images are delivered from imagedelivery.net with an account hash, image ID and variant instead. It is not on by default. Transformations can be requested on every Cloudflare zone that has transformations enabled. Its format=auto value automatically serves the most efficient format that the requesting browser supports. It is the default format option for a hosted image. Optimized images follow the same caching rules as the original image they were resized from, except the minimum cache time is one hour. Separately, Vary for Images is a cache feature available for Pro, Business, and Enterprise customers, not on Free. It caches per-format variants for an origin that sends Vary: Accept.
- imgix: a rendering API that derives variants from URL parameters such as fm for the output format and q for quality, applied on demand. Setting auto=format hands format choice to negotiation, with the AVIF-to-WebP-to-source fallback described above. Setting lossless=true forces lossless WebP. Its docs are the source of the 25 to 34% and 50% figures above.
- Cloudinary: recommends adding q_auto and f_auto to delivery URLs. q_auto (automatic quality) applies the best balance of visual quality and file size. f_auto (automatic format selection) delivers each image in the optimal format for the requesting browser. Any transformation strips metadata by default. Cloudinary strips all associated metadata from the transformed image file, except JFIFVersion, ResolutionUnit, XResolution, YResolution, Colorspace and DPI. The fl_keep_iptc flag can override this. Every plan can default quality and metadata stripping at the product-environment level. Defaulting format and size is the Optimize by default feature. This is Enterprise only. It is the one case where Cloudinary tells you not to add f_auto or q_auto yourself.
Watch out for
- Lossy encoding on sharp-edged content. Artifacts hide well in photographic detail. But web.dev warns that lossy compression may be less effective with imagery containing sharp edges such as line art, similarly stark details, or text. Encode diagrams, screenshots and logos lossless: PNG, or WebP or AVIF in lossless mode.
- Serving AVIF unconditionally. WebP is a widely supported format that works on all modern browsers. AVIF, in web.dev's words, is a newer image format, and while it isn't as widely supported as WebP, it does enjoy reasonably decent support across browsers. A client sent bytes it cannot decode shows a broken image. So AVIF must be gated on negotiation and never assumed.
- Color after metadata stripping: the risk runs the other way. Stripping metadata deletes the embedded ICC profile from the delivered file. But a correct pipeline bakes the profile into the pixels first. Cloudflare states that color profiles and EXIF rotation are applied to the image even if the metadata is discarded. Its metadata parameter, whose default is copyright, governs only JPEG output. For other output formats, all metadata will always be discarded. The pipeline that shifts colors is the one that deletes the profile without converting the pixels.
- Variant explosion. Each combination of width, format and quality is a separate cached object. web.dev's warning is that with many variations each variant requires another cache entry. It also warns that server costs can increase. It further warns that performance can degrade when an expired variant must be fetched from the origin again. This also dilutes cache hit ratio. Encoding is not free either. Cloudflare notes that AVIF encoding can be an order of magnitude slower than encoding to other formats. It also notes that if the image is too large to be quickly encoded to AVIF, then Cloudflare will fall back to WebP or JPEG.
- Invalidating derived copies. Derived URLs are not independently purgeable everywhere. Cloudflare does not support purging optimized images individually. URLs starting with /cdn-cgi/ cannot be purged at all. The documented route is that purging of the original image's URL will also purge all of its optimized versions. So plan the purge around master URLs, not variants.
- The one-hour floor. On Cloudflare, an optimized image is held for at least an hour, even if the original carried a shorter TTL. The documented way to get fresher images is to add must-revalidate to the Cache-Control header and to serve an ETag, which the Images service revalidates against.
Best practice
- Keep one high-quality master and derive every delivered copy from it through the pipeline. Never hand-maintain per-size files.
- Turn on automatic format selection (format=auto, f_auto, auto=format). Or write an explicit picture element with an AVIF source, a WebP source and a JPEG img fallback.
- Make the cache aware of negotiation. Send Vary: Accept and enable the CDN's image-variant handling. Or put the format in the URL instead. Getting this wrong is how one client's AVIF reaches a client that cannot decode it.
- Serve srcset with sizes. Always set width and height on the img. The HTML Standard notes this allows the user agent to allocate space for the image before it is downloaded.
- Resize to the displayed size instead of shipping one hero-sized file. Cap the largest variant.
- Keep metadata in the master, strip it in delivery, and confirm the pipeline applies the color profile, rather than merely deleting it.
- Encode line art, text and screenshots lossless. Reserve aggressive lossy settings for photographs.
- Cache derived copies with a long TTL. Revalidate with an ETag. Purge the master URL when the source changes, so every variant follows.
- Measure image bytes and LCP before and after. Modern formats may lower LCP. Whether they did on your pages is a measurement, not an assumption.
Examples
Cloudflare image resizing uses a URL:
<!-- Original: 2MB JPEG -->
<img src="/cdn-cgi/image/width=800,quality=80,format=auto/photos/hero.jpg">
<!-- Responsive with srcset -->
<img srcset="
/cdn-cgi/image/width=400,format=auto/photos/hero.jpg 400w,
/cdn-cgi/image/width=800,format=auto/photos/hero.jpg 800w,
/cdn-cgi/image/width=1200,format=auto/photos/hero.jpg 1200w"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px">An Nginx proxy can optimize images with libvips:
# Using ngx_small_light module
location ~ ^/images/(.+)$ {
small_light on;
small_light_getparam_mode on;
# /images/photo.jpg?w=400&q=80&of=webp
small_light_material_dir /var/www/images;
}
Frequently Asked Questions
Image optimization is delivering each image in the fewest bytes that still look right: re-encoding to a modern format such as WebP or AVIF, resizing to the size the page displays, tuning encoder quality, and stripping metadata. A CDN keeps one master and derives a cached copy per request.
Cloudflare image resizing uses a URL:
<!-- Original: 2MB JPEG -->
<img src="/cdn-cgi/image/width=800,quality=80,format=auto/photos/hero.jpg">
<!-- Responsive with srcset -->
<img srcset="
/cdn-cgi/image/width=400,format=auto/photos/hero.jpg 400w,
/cdn-cgi/image/width=800,format=auto/photos/hero.jpg 800w,
/cdn-cgi/image/width=1200,format=auto/photos/hero.jpg 1200w"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px">An Nginx proxy can optimize images with libvips:
# Using ngx_small_light module
location ~ ^/images/(.+)$ {
small_light on;
small_light_getparam_mode on;
# /images/photo.jpg?w=400&q=80&of=webp
small_light_material_dir /var/www/images;
}
Related CDN concepts include:
- Content-Encoding — The HTTP header naming the content codings applied to a body (gzip, br, zstd), which …