Skip to content
Keenpix docs
How it works

Caching

How Keenpix caches transforms and plays nicely with a CDN.

Optimizing an image is expensive; serving it again should be free. Keenpix caches every transform on disk and is built to sit behind a CDN.

The cache key

A result is keyed by everything that affects the output:

project + url + full transform option object

Two requests with identical effective parameters share one cached file. Requests that arrive while the first identical transform is still running share that same in-flight work too.

In-flight coalescing

If many identical requests arrive during a cold cache (e.g. a popular image after a deploy), Keenpix runs the fetch + encode once and shares the result, instead of doing the same work N times.

CDN-friendly responses

Every successful response sets:

Cache-Control: public, max-age=31536000, immutable
Accept-CH: Sec-CH-DPR, Sec-CH-Width, Sec-CH-Viewport-Width
Vary: Accept, Sec-CH-DPR, Sec-CH-Width, Sec-CH-Viewport-Width

Because the source URL and every transform live in the URL, the response is immutable. Configure your CDN to cache /img/* responses, including the full query string. For Cloudflare, that usually means a Cache Rule for the endpoint; orange-cloud proxying alone is not enough for every dynamic-looking path.

Vary: Accept keeps per-format variants correct under fmt=auto only when your CDN supports caching separate variants by Accept. On CDNs that do not, prefer explicit fmt=avif, fmt=webp, fmt=jpeg, fmt=png, or fmt=svg URLs. Explicit formats improve cache predictability, but they also disable browser-based AVIF/WebP negotiation for that URL. fmt=svg is one of those explicit formats; fmt=auto never preserves SVG output.

For the first image request, and for a delivery hostname different from the page hostname, also advertise the hints on the HTML response and delegate them with a Permissions Policy, for example:

Accept-CH: Sec-CH-DPR, Sec-CH-Width, Sec-CH-Viewport-Width
Permissions-Policy: ch-dpr=(self "https://images.example.com"), ch-width=(self "https://images.example.com"), ch-viewport-width=(self "https://images.example.com")

Browsers may omit hints for privacy or compatibility reasons, so Keenpix always falls back to project defaults.

Where does Keenpix store cached images?

Production uses memory → Dragonfly → Cloudflare R2 or MaxIO. Lower-tier hits are promoted, durable writes happen first, and KEENPIX_CACHE_DELETE_AFTER_MS removes an expired variant from the complete chain. Local source development without those services uses the atomic disk cache at KEENPIX_CACHE_DIR. See Configuration for size limits and eviction.

The full effective transform object is in the cache key. That includes resolved Client Hint dimensions and project watermark configuration, so neither feature can cross-contaminate variants.

On this page