VeroXM Docs

CDN & Media Pipeline

Every image uploaded to VeroXM is automatically processed into the variants a real front end actually needs, and every content change can automatically purge your CDN's cache - both without any extra step at upload or publish time.

What happens on every image upload

MediaService runs each uploaded image through the same pipeline (built on sharp) before it is ever served:

  • A same-format thumbnail, resized to 600px tall, for the media grid and picker.
  • A WebP-encoded thumbnail, independent of the same-format one - a smaller download for a thumbnail-heavy grid, served via a <picture> element that falls back to the original format automatically.
  • A full-resolution WebP re-encode of the original, for pages that render the image itself rather than a thumbnail card.
  • A dominant-color tag, computed from a 1x1 average resize, used as an input to auto-tagging.

A format sharp cannot re-encode (BMP, and some GIFs) falls back to storing the original bytes as its own thumbnail rather than failing the upload - every image still gets a working thumbUrl, even if not every variant exists for it.

What the Content API returns for an image field
{
  "fullUrl": "https://.../hero.jpg",
  "fullWebpUrl": "https://.../hero.webp",
  "thumbUrl": "https://.../hero-thumb.jpg",
  "thumbWebpUrl": "https://.../hero-thumb.webp",
  "width": 2400,
  "height": 1350
}

Storage providers

Where those files actually live is a swap-in StorageProvider, chosen per environment by a disk setting - the transform pipeline above runs identically regardless of which one is active, since it lives behind the interface rather than inside any one provider:

ProviderBacking store
localDisk on the API server - the default for development.
s3Amazon S3 (or an S3-compatible bucket).
r2Cloudflare R2 - pairs naturally with Cloudflare CDN purging below.

See Storage & Email Integrations for env var configuration, the object-key layout, and advanced deployment patterns for S3 and R2.

CDN cache purging

A project can connect a Cloudflare zone from its Integrations settings (zone id + API token). Once connected, every content.published, content.updated, and content.deleted event automatically triggers a purge - no manual cache-clearing step after a content change.

Purges run on the same background job queue as everything else, with a short coalescing delay: several rapid saves to the same project collapse into a single purge call rather than one per save, and a failed purge retries with backoff (3 attempts, 2s/4s) instead of silently leaving stale content behind the CDN.

One integration proves the pattern

Cloudflare is the first CDN provider implemented, following the same “pick one real vendor, prove the pattern” approach VeroXM uses for its other third-party integrations - the purge job's logic (config lookup, coalescing, retries) is already provider-agnostic, so adding a second CDN vendor is a matter of implementing one more purge call, not redesigning the pipeline.