LiftgateSign in

Liftgate

Images

A verification surface for the Cloudflare Images pipeline. Every sample below is the same handful of PNGs in public/images/ — what differs is the route each one takes to the browser.

On :3000 (vinext dev) /_next/image is a passthrough and serves the original bytes — that proves the markup, not the binding. On :1337 (alchemy/workerd) the same URLs resolve the IMAGES binding and come back resized and re-encoded.

Optimized — the same source at three widths

One 1600×1200 source. If the optimizer is live, the 384px render transfers a small fraction of the 1.3MB original and arrives as AVIF or WebP rather than PNG. Measured on :1337, 2026-08-09: 2,232 bytes at w=128 rising to 26,466 at w=1920, against a 1.3MB source.

384px wide
Smallest render — the clearest size win.
Resolution test chart rendered at 384px
/_next/image?url=%2Fimages%2Ftest-chart.png&w=384&q=75
640px wide
Mid render, default quality 75.
Resolution test chart rendered at 640px
/_next/image?url=%2Fimages%2Ftest-chart.png&w=640&q=75
640px, quality 25
Same width, lower quality. NOTE: identical to q=75 under `alchemy dev` — the local emulator ignores quality (see the page header).
Resolution test chart at 640px, quality 25
/_next/image?url=%2Fimages%2Ftest-chart.png&w=640&q=25

Optimized vs. raw — the control

The pair that makes a silent failure visible: both should LOOK identical, and the network panel should disagree about how many bytes it cost. If the left one 404s or 500s while the right still renders, the optimizer is the broken half — not the asset.

Through the optimizer
next/image → /_next/image → IMAGES binding.
Gradient wordmark plate, optimized
/_next/image?url=%2Fimages%2Fliftgate-wordmark.png&w=640&q=75
Static asset, untouched
A plain <img> served straight from public/.
Gradient wordmark plate, unoptimized
/images/liftgate-wordmark.png

Layout modes

fill + object-cover
No intrinsic size — the parent decides, as in a card banner.
Portrait plate cropped to a banner
/_next/image?url=%2Fimages%2Fwarehouse.png&w=640&q=75
priority (preloaded)
Eager, no lazy boundary — the above-the-fold case.
Portrait plate at 256px, eagerly loaded
/_next/image?url=%2Fimages%2Fwarehouse.png&w=256&q=75

Checking it from the shell

A transform is confirmed by the response headers, not by the render — content-type should stop saying image/png:

curl -sI -H 'accept: image/avif,image/webp,*/*' 'http://localhost:1337/_next/image?url=%2Fimages%2Ftest-chart.png&w=384&q=75'