UI Drafter Blog

Nginx
Conditionally Serve AVIF

October 2, 2020
Eric Fortis

Why serving next generation images with Nginx?

Here's how

The images are uploaded with the extension appended:

For dispatching the most efficient format, Nginx checks the Accept request header. For example, Chrome 85 and up say they support AVIF by sending its MIME type:

Accept: image/avif,image/webp,image/apng,image/*,*/*;q=0.8

nginx.conf 1

http {
  # ...
  map $http_accept $img_ext {
    ~avif    '.avif';
    ~webp    '.webp';
    default  '';
  }

  server {
    # ...
    location /images {
      add_header  Vary Accept;
      try_files   $uri$img_ext $uri =404;
    }
  }
}

On requests under /images, Nginx checks the Accept header ($http_accept) to define the custom variable $img_ext with the extension associated to the first matched regex of the map.

Then, try_files checks if there's a file with that extension appended, e.g., foo.jpg.avif, and serves it. The middle $uri is a fail-safe, for instance, maybe the AVIF isn't uploaded yet.

Lastly, Vary: Accept is set as a response header. This is only needed if the server has caching reverse proxies in front (e.g., intercepting CDNs). Otherwise, those proxies would always serve the same format sent to the first client that requested the particular image.2

References

1. Eugene Lazutkin (2014) Serve files with Nginx conditionally 2. Rogier Mulhuijzen (2014) Best Practices for Using the Vary Header