Use AVIF and WebP image formats

Clarification
You keep uploading JPEG/PNG as before; Docly converts on serving, and the file extension on the display name in the image URL decides the output format (…/1200x800x0/produkt.webp ⇒ WebP). WebP has universal browser support, so <img src="….webp"> is enough on its own. AVIF must sit inside a <picture> with WebP/JPEG fallback, because Docly does not negotiate format via the Accept header — without a fallback, visitors without AVIF support see nothing. A safe site-wide default is images.defaultFormat: webp in #/site.json; avoid avif as a global default.
Applies to: Hash templatesImages

What you'll see

You want smaller image files and a better performance score. AVIF and WebP produce noticeably smaller files than JPEG/PNG at the same perceived quality, which helps Core Web Vitals and the LCP of image-heavy pages. The question that follows is a markup one:

<img src="….avif">

Should the new formats be requested with a plain <img>, or does something more need to wrap them? Getting this wrong with AVIF does not throw an error in your own browser — it silently breaks the image for every visitor whose browser cannot decode AVIF.

What's actually happening

You still upload JPEG/PNG. You do not pre-convert anything. Docly converts a scaled copy of the image on serving, on demand, and the output format is chosen solely from the file extension of the display name in the image URL. So …/1200x800x0/produkt.webp is served as WebP, and …/1200x800x0/produkt.avif is served as AVIF. The extensions that steer the format are .jpg, .jpeg, .png, .webp and .avif. .gif and .svg get no conversion.

WebP alone → <img> is enough. WebP has universal browser support, so a single <img src="….webp"> needs no fallback.

AVIF → <picture> is required, not overkill. Docly picks the image format only from the extension in the URL. There is no Accept-header negotiation. An <img src="….avif"> therefore delivers AVIF to everyone — including browsers that cannot display it, where the image simply disappears. With <picture> it is the browser, not the server, that chooses: it takes the first <source> with a type it supports. That is the only mechanism that gives AVIF safely in Docly today.

What to do

1. Simple variant — WebP, no fallback needed. WebP support is universal, so a plain <img> with a .webp display name is all you need:

<img src="#linkImage(f.Image1, 1200, 800, 0, 'produktnavn.webp')#"
     width="1200" height="800" loading="lazy" decoding="async"
     alt="#enc(f.Title)#">

2. Recommended variant — AVIF with fallback. Wrap AVIF in a <picture> with WebP and JPEG fallback. The order is significant: the browser takes the first <source> it supports, so AVIF comes before WebP:

<picture>
  <source type="image/avif"
          srcset="#linkImage(f.Image1, 1200, 800, 0, 'produktnavn.avif')#">
  <source type="image/webp"
          srcset="#linkImage(f.Image1, 1200, 800, 0, 'produktnavn.webp')#">
  <img src="#linkImage(f.Image1, 1200, 800, 0, 'produktnavn.jpg')#"
       width="1200" height="800" loading="lazy" decoding="async"
       alt="#enc(f.Title)#">
</picture>

The <img> inside <picture> is the mandatory fallback — it carries the alt, width/height and loading. Always set width/height to prevent layout shift, and use loading="lazy" on below-the-fold images — not on the top LCP image. For transparent images, the fallback must be .png, not .jpg.

3. Site-wide default — #/site.jsonimages.defaultFormat. This applies only when the URL has no format-steering extension. Write keys in camelCase:

{
  "images": {
    "defaultFormat": "webp"
  }
}

webp is the safe global default. Avoid "defaultFormat": "avif" as a global default: without a <picture>, every visitor gets AVIF, and those who cannot decode it see nothing.

4. Pitfalls.

  • SVG and GIF are not converted. Do not give them a .webp extension and do not wrap SVG in <picture>.
  • The size policy enforces WxHxM, not the extension. The dimensions in the URL (e.g. 1200x800x0) are what the policy checks — three formats at the same size therefore count as one size. New sizes go in allowedSizes.
  • The default open size policy does not support WebP/AVIF. Under images.sizePolicy: "open" (the default) a .webp/.avif display name is served as JPEG regardless of the extension. Set sizePolicy to auto or strict in #/site.json for the format to take effect — see Restrict and register image sizes for how to switch the policy.
  • Turn on caching before adopting AVIF. Derived images are cached per unique URL (size + format) only when caching is enabled for the site; AVIF encoding is heavy, so re-encoding on every request is costly.
  • 429 Too Many Requests. Docly has a guard against many concurrent scalings that only triggers on a cache miss. AVIF encoding is heavy, so warm the cache by requesting the new sizes/formats once after publishing, instead of letting the first real traffic burst hit an unwarmed cache.
  • PNG is the fallback for transparent images — both WebP and AVIF preserve alpha, but the <img> fallback must be .png so transparency survives.

Checklist.

  • WebP only? A plain <img src="….webp"> is enough.
  • AVIF? Always inside <picture> with WebP → JPEG/PNG fallback, AVIF <source> first.
  • The <img> fallback carries alt, width/height and loading.
  • Set width/height; use loading="lazy" below the fold, not on the LCP image.
  • Transparent image? Fallback is .png, not .jpg.
  • Global default in #/site.json is webp, never avif.
  • Caching is on before you adopt AVIF.
  • No .webp/.avif extension on SVG or GIF.
  • images.sizePolicy is auto or strict (not the default open) so WebP/AVIF actually take effect.