Serve Next-Gen Images on Nginx: Map, Try_Files, Cache

November 06, 2025 by Andrew Smith

So you’ve built a blazing-fast website, and you want your images to be just as zippy. You’ve heard that WebP and AVIF rock for performance, but now you’re diving into the world of Nginx config files and scratching your head. Don’t worry… we got you!

TL;DR: Modern image formats like WebP and AVIF save bandwidth and load faster. You can serve them without changing your code using map, try_files, and caching magic in Nginx. Clients get the best image for their browser without even knowing it. And no, you don’t have to learn wizard spells to set it up (but it does feel like magic!).

Why Next-Gen Images?

Let’s start with the basics. Why should you care about WebP or AVIF?

  • Smaller files = faster loading pages.
  • Same (or better) quality than JPEG and PNG.
  • They’re supported by most modern browsers.

So if you’re serious about speed, next-gen image formats are a no-brainer.

How Browsers Ask for Formats

Browsers tell servers what formats they like using the Accept header.

For example, Chrome might say:

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

Cool, right? We can read that in Nginx and respond with the image they prefer. And that’s where the magic starts…

Step 1: Use map to Decode Requests

We’ll use the map directive to detect what format the client wants. It’s like a chooser tool.

map $http_accept $image_ext {
    default "";
    "~image/avif" ".avif";
    "~image/webp" ".webp";
}

This tells Nginx: if the header includes “image/avif”, use “.avif”. If it includes “image/webp”, use “.webp”. Otherwise… fall back to the original file like “.jpg” or “.png”.

Now we have a custom variable ($image_ext) to use later!

Step 2: Use try_files to Select the Best Format

Next, we’ll set up a location block that serves the right file based on what’s available and what the browser supports.

location /images/ {
    try_files 
        $uri$image_ext 
        $uri 
        =404;
}

Let’s break that down:

  • $uri$image_ext: First try a next-gen format like image.webp or image.avif.
  • $uri: If that fails, try the original like image.jpg.
  • =404: If nothing works, send a 404 error.

It’s that simple! Now, when a browser supports AVIF or WebP, it gets the lightweight version. Older browsers still get the image in the old format. Everyone wins.

Step 3: Enable Caching (Super Important!)

Let’s talk cache — the magical kingdom where performance dreams come true.

Here’s the tricky part. Same image file, but you’re serving it in different formats to different browsers. That can mess with caching if you’re not careful.

To fix that, we vary the cache by the Accept header. That way, one browser’s AVIF doesn’t end up served to a browser that can’t handle it.

location /images/ {
    add_header Vary Accept;
    try_files 
        $uri$image_ext 
        $uri 
        =404;
}

The Vary: Accept header tells caches (like CDNs and browsers): “Hey, this resource depends on what the browser accepts.” That keeps things clean and safe.

Optional: Generate WebP and AVIF

If you’re thinking “Wait! I don’t even have WebP or AVIF images yet…”, don’t panic!

Here are some ways to convert your images:

  • CLI tools: Use cwebp or avifenc in bulk.
  • ImageMagick: Easy for scripting.
  • Online converters: Great for testing.

And if you’re fancy, use a build step to generate these during deploy. Set it and forget it!

Bonus: Content Negotiation with Fallbacks

Sometimes, a client says it supports WebP but doesn’t actually display it well. Looking at you, some weird Android browsers!

If you want more precise control, you can add fancy logic with if blocks — but beware, they get messy in Nginx.

We recommend serving WebP and AVIF only if you’re confident they render properly. Use real image testing tools or browser-specific overrides if needed. In most cases though, using map plus try_files is safe and simple.

Security Tip: Don’t Leak Files!

Make sure the location you serve images from doesn’t allow unwanted file browsing or attacks.

location /images/ {
    autoindex off;
    internal;
    try_files 
        $uri$image_ext 
        $uri 
        =404;
}

internal; means only other Nginx rules can point here. It keeps random users from poking around your image folders.

Test Everything (Then Test Again)

Not seeing next-gen images served? Check:

  • Are your WebP/AVIF files named correctly and sitting next to the originals?
  • Did you reload Nginx after updating the config?
  • Are your test browsers actually requesting image/webp or image/avif in the Accept header?

Use curl -H "Accept: image/webp" or browser DevTools to debug headers and responses.

Final Thoughts: Clean, Fast, Future-Proof

With just a few lines of Nginx config, you can boost site speed dramatically. No need to rewrite HTML or mess up URLs. And your visitors get lightning-fast images tailored to their browser’s abilities.

Let’s recap:

  • Use map to detect preferred image format from request headers.
  • Use try_files to serve AVIF or WebP if they exist.
  • Add Vary: Accept to cache smartly and safely.

Once this is in place, your site is one big step closer to perfection. Smooth, sleek, and super snappy!

Now go forth and optimize!