Build-time image processing works fine until you have 10,000 images, user-uploaded content, or a CMS that spits out full-resolution originals. At that point, the build takes 45 minutes, your CI storage balloons, and adding a new image size means reprocessing everything.
CDN image transformation solves this by moving processing to the edge. You upload one high-quality source image and request any size, format, or crop via URL parameters. The CDN processes it once, caches the result globally, and serves subsequent requests from cache at full CDN speed.
How CDN Image Transformation Works
The flow is the same across all providers:
- Client requests an image with transformation parameters (resize to 800px, auto-format)
- CDN edge node checks its cache for this exact transformation
- Cache miss: CDN fetches the original from your origin, applies transformations, caches the result, and responds
- Cache hit: CDN responds immediately from cache
First-request latency: A cache miss adds 50-500ms depending on the transformation (simple resize is fast, AVIF encoding is slow). After that, responses are served from cache with zero processing overhead.
Auto-format detection: When you specify format=auto, the CDN reads the client's Accept header. If it contains image/avif, the CDN returns AVIF. If it contains image/webp, it returns WebP. Otherwise, it returns JPG. This means a single <img> tag gets optimal format delivery without the <picture> element:
<img src="/cdn-cgi/image/format=auto,width=800/photo.jpg" alt="Photo" width="800" height="600">The browser sends its Accept header, the CDN handles the rest. You Vary on Accept to ensure caches store separate entries per format.
Cloudflare Image Resizing
Cloudflare's image transformation is built into their CDN and available on Pro+ plans ($20/mo). It can be used via URL path conventions or programmatically via Workers.
URL path syntax:
<!-- Basic resize with auto-format -->
<img src="/cdn-cgi/image/width=800,quality=80,format=auto/images/hero.jpg">
<!-- Responsive srcset -->
<img
srcset="/cdn-cgi/image/w=400,f=auto/hero.jpg 400w,
/cdn-cgi/image/w=800,f=auto/hero.jpg 800w,
/cdn-cgi/image/w=1200,f=auto/hero.jpg 1200w"
sizes="(max-width: 768px) 100vw, 50vw"
src="/cdn-cgi/image/w=800,f=auto/hero.jpg"
alt="Hero">Workers integration (maximum control):
export default {
async fetch(request) {
const url = new URL(request.url);
if (!url.pathname.startsWith('/images/')) return fetch(request);
const width = parseInt(url.searchParams.get('w')) || 800;
const quality = parseInt(url.searchParams.get('q')) || 80;
return fetch(request, {
cf: {
image: {
width,
quality,
format: 'auto',
fit: 'cover',
metadata: 'none', // Strip EXIF
sharpen: 1,
}
}
});
}
};Strengths: No separate service — runs on your existing Cloudflare zone. Workers integration enables custom logic (A/B testing images, role-based watermarks, device-specific crops). No per-image billing — included with the plan.
Limitations: Only available on Pro+ plans. Fewer built-in transformations than imgix or Cloudinary (no text overlays, no chained transforms). Maximum output dimension of 12,000px.
imgix
imgix is a dedicated image CDN that transforms images via URL parameters. You point it at your origin (S3, GCS, web folder) and access images through an imgix subdomain.
<!-- Basic resize -->
<img src="https://example.imgix.net/photos/hero.jpg?w=800&auto=format,compress">
<!-- Responsive with srcset -->
<img
srcset="https://example.imgix.net/hero.jpg?w=400&auto=format 400w,
https://example.imgix.net/hero.jpg?w=800&auto=format 800w,
https://example.imgix.net/hero.jpg?w=1200&auto=format 1200w"
sizes="(max-width: 768px) 100vw, 50vw"
src="https://example.imgix.net/hero.jpg?w=800&auto=format"
alt="Hero">
<!-- Advanced: face detection crop + blur + text overlay -->
<img src="https://example.imgix.net/team.jpg?w=300&h=300&fit=facearea&facepad=2">Key parameters:
w,h— width, heightfit— crop, clip, fill, fillmax, facearea, max, min, scaleauto=format— content-negotiated format (AVIF/WebP/JPG)auto=compress— automatic quality optimizationq— manual quality (0-100)blur— gaussian blur (0-2000)txt,txt-size,txt-color— text overlays
Strengths: Extremely fast (purpose-built infrastructure, not bolted onto a general CDN). Rich parameter API (300+ options). Face detection, focal point cropping, PDF rendering, video thumbnails. URL signing for access control. Client libraries for every framework (React, Vue, Next.js, Gatsby).
Limitations: Separate service and domain (CORS considerations). Per-origin pricing that scales with bandwidth. No compute at the edge (unlike Cloudflare Workers).
Cloudinary
Cloudinary is the most feature-rich option — image and video transformation, asset management, AI-powered features, and upload widgets. It uses path-based transformation syntax:
<!-- Basic resize -->
<img src="https://res.cloudinary.com/demo/image/upload/w_800,f_auto,q_auto/hero.jpg">
<!-- Responsive -->
<img
srcset="https://res.cloudinary.com/demo/image/upload/w_400,f_auto,q_auto/hero.jpg 400w,
https://res.cloudinary.com/demo/image/upload/w_800,f_auto,q_auto/hero.jpg 800w,
https://res.cloudinary.com/demo/image/upload/w_1200,f_auto,q_auto/hero.jpg 1200w"
sizes="(max-width: 768px) 100vw, 50vw"
src="https://res.cloudinary.com/demo/image/upload/w_800,f_auto,q_auto/hero.jpg"
alt="Hero">
<!-- Chained transformations: resize, then round corners, then overlay logo -->
<img src="https://res.cloudinary.com/demo/image/upload/w_600,h_400,c_fill/r_20/l_logo,g_south_east,w_100,o_70/product.jpg">Key transformations:
w_,h_— width, heightc_fill,c_fit,c_crop— resize modesf_auto— auto-format (AVIF/WebP/JPG)q_auto— perceptual quality optimizatione_— effects (blur, sharpen, grayscale, art filters)l_— overlays (image, text, video)g_— gravity/positioning
Strengths: Most transformation options of any service. Built-in asset management (DAM). Upload widgets, client SDKs, AI tagging, background removal, video transcoding. q_auto uses perceptual quality analysis per-image (not a static quality number).
Limitations: Complex pricing (credits system based on transformations + bandwidth + storage). URL syntax is verbose. Lock-in risk — your image URLs contain the Cloudinary domain, so migrating requires URL rewriting everywhere.
Feature and Cost Comparison
| Feature | Cloudflare | imgix | Cloudinary |
|---|---|---|---|
| Auto-format (AVIF/WebP) | Yes | Yes | Yes |
| Auto-quality | No (manual) | Yes (auto=compress) | Yes (q_auto) |
| Face detection crop | No | Yes | Yes |
| Text overlays | No | Yes | Yes |
| Chained transforms | No | Limited | Yes |
| Edge compute | Yes (Workers) | No | No |
| Video support | No | Limited | Yes |
| Asset management | No | No | Yes (DAM) |
| Self-hosted origin | Yes (your origin) | Yes (point to S3/GCS/URL) | No (upload to Cloudinary) |
| Starting price | $20/mo (Pro plan) | $100/mo (10K origins) | Free (25 credits) |
Recommendation: If you're already on Cloudflare Pro, start with Image Resizing — it's included and requires no additional service. If you need advanced features (face detection, overlays, DAM), Cloudinary has the richest feature set. If you want the fastest dedicated image CDN with a clean URL API, imgix is the sweet spot.
Self-Hosted Alternatives
If you don't want a paid service or need to keep images on-premises, self-hosted image servers work well for moderate traffic:
thumbor (Python):
# URL-based resizing with smart cropping
http://localhost:8888/unsafe/800x600/smart/example.com/images/photo.jpg
# Docker deploy
docker run -p 8888:8888 thumbororg/thumborimaginary (Go, libvips-backed):
# Resize via query parameters
GET http://localhost:9000/resize?width=800&type=auto&url=http://origin/photo.jpg
# Docker deploy
docker run -p 9000:9000 h2non/imaginarysharp as a microservice:
// Express server with sharp
import express from 'express';
import sharp from 'sharp';
const app = express();
app.get('/images/:name', async (req, res) => {
const { w = 800, q = 80, f = 'webp' } = req.query;
const buffer = await sharp(`./originals/${req.params.name}`)
.resize(parseInt(w))
.toFormat(f, { quality: parseInt(q) })
.toBuffer();
res.type(`image/${f}`).send(buffer);
});
Tradeoff: Self-hosted solutions require you to handle caching (put Varnish or Nginx caching in front), scaling (CPU-bound processing), and security (URL signing to prevent abuse). CDN services handle all of this.
CDN image transformation is the pragmatic choice for any site with more than a few dozen images. The combination of auto-format, auto-quality, and on-demand resizing eliminates the entire build-time pipeline while delivering smaller files to every user. The cost is justified by the engineering time saved and the bandwidth reduction.
For sites that don't need real-time transformation — static sites with a known set of images — build-time processing with sharp is still perfectly valid. But the moment you have user uploads, CMS-managed images, or thousands of pages, CDN transformation pays for itself immediately.