Media · Images

Resize, optimize, and serve images at the edge

After this lesson you'll be able to upload an image to Cloudflare Images, request resized/format-converted variants via URL, and explain the pricing and configuration split between hosted storage and transform-only usage.

Cloudflare Images is a managed pipeline for the three things almost every app needs to do with pictures: get them stored somewhere, produce the right size/format for each surface (thumbnail, hero banner, retina, mobile), and serve them fast worldwide. It bundles three capabilities that used to require separate infrastructure: a storage layer for uploaded originals, an on-the-fly transformation engine (resize, crop, format conversion to WebP/AVIF, quality tuning), and delivery through Cloudflare's global CDN so transformed variants are cached at the edge close to the requester. You upload one original; every consumer gets a version sized and encoded for them, generated on first request and cached after that.

Two source modes, one product. Cloudflare's current docs describe Images as covering two setups under one pricing/config umbrella: (1) transforming images that already live in your own storage (R2, S3, any origin URL) — you keep your storage, Cloudflare just resizes/converts on request — or (2) uploading images to Cloudflare's own managed storage and letting Images host and serve them entirely. Older Cloudflare material calls option (1) "Image Resizing" as if it were a separate product; today it's one feature set with two different cost structures depending on whether Cloudflare is storing the bytes for you. That distinction is the pitfall at the end of this lesson.

How it works

Two URL shapes cover the two source modes:

In both cases, <OPTIONS> is a comma-separated list — width/w, height/h, fit (cover, contain, crop, scale-down, etc.), quality/q, and format/f. format=auto is the one worth defaulting to almost everywhere: Cloudflare inspects the requesting browser's Accept header and serves AVIF or WebP where supported, falling back to JPEG/PNG otherwise — one URL, best format per client, and it still counts as a single billable transformation no matter how many different encoded outputs it produces.

The first request for a given image + option combination does the actual resize/encode work and the result is cached at Cloudflare's edge; subsequent requests for that same combination are served from cache without repeating the transform. That's why pricing is based on unique transformations per month, not total requests.

Worked example

Upload an image to Cloudflare's hosted storage via the API:

curl -X POST \
  "https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/images/v1" \
  -H "Authorization: Bearer <API_TOKEN>" \
  -F "file=@./product-photo.jpg" \
  -F "metadata={\"sku\":\"SKU-1284\"}"

A successful response includes the image's ID and its delivery URL variants:

{
  "result": {
    "id": "3e4a1a9b-...-9c2f",
    "filename": "product-photo.jpg",
    "uploaded": "2026-07-03T10:15:00Z",
    "variants": [
      "https://imagedelivery.net/<ACCOUNT_HASH>/3e4a1a9b-...-9c2f/public"
    ]
  },
  "success": true,
  "errors": [],
  "messages": []
}

Request a resized, format-converted variant on the fly by putting options straight in the URL (requires flexible variants enabled on the account — otherwise you request one of your predefined named variants instead, e.g. /thumbnail):

<!-- 400px wide, best format for the browser, quality 85 -->
<img
  src="https://imagedelivery.net/<ACCOUNT_HASH>/3e4a1a9b-...-9c2f/w=400,format=auto,quality=85"
  alt="Product photo"
>

<!-- square crop for a grid thumbnail -->
<img
  src="https://imagedelivery.net/<ACCOUNT_HASH>/3e4a1a9b-...-9c2f/w=200,h=200,fit=cover,format=auto"
  alt="Product thumbnail"
>

Same idea against an image that stays in your own storage (e.g. R2 or an existing web origin), using your zone instead of imagedelivery.net:

https://shop.example.com/cdn-cgi/image/width=800,format=auto,fit=scale-down/images/product-photo.jpg

Pricing

As of this writing, Cloudflare prices the two source modes separately:

DimensionRate
Transformations (either source mode)First 5,000 unique transformations/month free, then $0.50 per 1,000 unique transformations/month
Images stored (Cloudflare-hosted storage only)$5 per 100,000 images stored/month
Images delivered (Cloudflare-hosted storage only)$1 per 100,000 images delivered/month

A "unique transformation" is one billable unit per source image + option combination per month — requesting the same width/format/quality repeatedly (cache hits) doesn't multiply the charge, and format=auto serving AVIF to one client and WebP to another still counts once. Transforming images that stay in your own origin storage only incurs the transformation charge — there's no separate storage or delivery line item, because Cloudflare isn't storing the bytes. Pricing changes; confirm current numbers on the live pricing page linked below before quoting them.

Use cases

Pitfall: treating "Images" and "Image Resizing" as interchangeable when scoping cost or config. Transforming an image that lives in your own storage (zone-based /cdn-cgi/image/ URLs) is billed purely on unique transformations — Cloudflare never stores the original, so there's nothing to configure beyond enabling the feature on your zone. Uploading to Cloudflare's own hosted storage (imagedelivery.net URLs) adds storage and delivery charges on top of transformations, requires managing images through the Images API/dashboard, and needs variants (named or flexible) configured before you can request resized URLs. Estimating cost or setting up delivery for one mode using the other mode's numbers or configuration steps is a common and easy mistake — check which source mode a given image actually uses before you price it out or debug why a variant URL 404s.
Primary source

Cloudflare Images documentation covers both source modes; pair it with the Images pricing page for current, authoritative numbers, since pricing is subject to change.

You're transforming images that stay in your own R2 bucket using zone-based /cdn-cgi/image/... URLs (not uploading to Cloudflare's hosted storage). Which pricing line items apply?
Without scrolling up: what makes a transformation "unique" for billing purposes, and why doesn't requesting format=auto across many different browsers multiply the charge?
Reveal

A unique transformation is one billable unit per source image + option combination per month. Once the first request generates and caches a given combination, later requests for that same combination — including repeated format=auto requests that resolve to AVIF for one browser and WebP for another — are served from the edge cache and don't count as additional billable transformations.

Anything above unclear — the two URL shapes, flexible vs. named variants, or how the source-mode split affects your own architecture? Ask your AI teacher before moving on.
← Previous: Pages or Workers? Choosing the right compute model Next: Ingest and deliver video with Stream →