Image CDNs and on-the-fly transformation

Origin-based versus URL-based transformation, resize and quality parameters, format negotiation, caching generated variants, and the pricing shapes that catch people out.

Two ways to transform

ApproachHow it worksStrengthWeakness
Origin transformationYou generate variants at upload or build timeFull control, cheap at request timeEvery new size requires a backfill
URL-based transformationThe CDN generates the variant on demandAny size, immediatelyFirst request is slow; each variant is billed
HybridCommon sizes pre-generated, the rest on demandFast for the common caseTwo code paths to keep consistent
<!-- URL-based transformation: the variant is described in the URL -->
<img src="https://cdn.example.com/img/hero.jpg?w=800&q=75&fm=webp"
     srcset="https://cdn.example.com/img/hero.jpg?w=400&q=75&fm=webp 400w,
             https://cdn.example.com/img/hero.jpg?w=800&q=75&fm=webp 800w,
             https://cdn.example.com/img/hero.jpg?w=1600&q=75&fm=webp 1600w"
     sizes="(max-width: 600px) 100vw, 60vw"
     width="1600" height="900" alt="Order dashboard" />
  • Every distinct parameter combination is a separate cached object. Use a small, fixed set of widths rather than a free-form value.
  • Always set a width and height on the element. A transformed image that changes size on load causes layout shift.
  • Be careful with automatic format negotiation in srcset: a CDN that serves a different format per browser also needs Vary: Accept, and many do not send it.

Caching generated variants

# a transformed variant is deterministic, so it can be cached hard
Cache-Control: public, max-age=31536000, immutable

# the transformation response must vary on what actually changes it
Vary: Accept

# and a limit on the number of generated variants avoids runaway cost
# e.g. allow w in {200,400,800,1200,1600}, q fixed at 75
PitfallWhat happensPrevention
Unbounded width valuesThousands of variants, all billed and storedWhitelist allowed parameters
Slow first requestThe first user waits for the transformPre-warm the common variants after deploy
Transform billed per requestA cache bypass makes every view a transformVerify the cache headers on the variant
Signed URLs on the image pathThe cache key includes the signatureSign the page, not each image, or use a stable signature
Format negotiation without VaryA WebP served to a client expecting JPEGSet the header, or use picture markup
Quality set per requestExtra variants for an invisible differenceFix quality in the transform configuration
# is a variant cached after the first request?
curl -sI "https://cdn.example.com/img/hero.jpg?w=800&q=75" | grep -iE "age|cache-control|content-type"
curl -sI "https://cdn.example.com/img/hero.jpg?w=800&q=75" | grep -iE "age|cache-control|content-type"

# does the CDN vary by Accept?
curl -sI -H "Accept: image/webp" "https://cdn.example.com/img/hero.jpg?w=800" \
  | grep -iE "content-type|vary"

Cost and quality

  1. Fix the set of widths your layout actually uses. Three or four is usually enough.
  2. Pre-generate or pre-warm the most common variants right after a deploy, so no user pays the first-request cost.
  3. Set quality once at the CDN level and do not expose it in the URL. The difference between 75 and 80 is not visible and doubles the variants.
  4. Watch the ratio of transformations to cache hits. If transformations grow with traffic, caching is broken.
  5. Measure real quality with a screenshot comparison at your chosen settings rather than assuming lower is fine.
SettingCommon valueNotes
Width400, 800, 1200, 1600Match the breakpoints in the layout
Quality70-80 for JPEG and WebPBelow 70 shows artefacts on gradients
Formatauto or explicitExplicit is easier to reason about
Fitcover for cardsCrops instead of distorting
MetadataStrippedBoth smaller and better for privacy
UpscalingDisabledNever generate a variant larger than the source
⚠️
An image CDN charges for the transform and then for the egress of every variant. Allowing arbitrary width values in a query string means any visitor can generate and consume unlimited billable transformations by requesting unusual sizes - whitelist the parameters or the bill becomes a denial-of-service vector.

FAQ

Should I use an image CDN at all?
If you serve images at more than one size, yes. Doing it yourself means maintaining a pipeline, storage for every variant and a resizing service, and the CDN usually does it better and cheaper.
What about art direction?
URL parameters handle resizing and cropping. Changing the composition per breakpoint needs different source images chosen in markup with ``, which is a design decision, not a transform.

Static asset optimisation: compression and modern images Video and large file delivery

Last refreshed 2026-09-18.