Nginx Cache-Control Headers Configuration

Browser caching decides whether a returning visitor re-downloads your files. The safe pattern is to cache fingerprinted assets for a year, because their URLs change with their content, and to make the HTML page that references them revalidate every time.

Fingerprinted assets can be immutable

Build tools such as Vite and webpack put a content hash in file names (app.3f9a1c.js). A given URL then never changes, so the browser may keep it for a year and, with the immutable directive, skip revalidation even on reload. Choosing the value with a map keeps it working in front of a proxied app too: a regex location with no handler of its own would serve files from the root directory and shadow the proxy.

map $uri $cache_control {
    default "";
    ~*\.(?:js|mjs|css|woff2|woff)$   "public, max-age=31536000, immutable";
}

# in the server block
add_header Cache-Control $cache_control always;

HTML must revalidate

The HTML file is what names the current asset URLs. If it is cached for long, visitors keep loading the old bundle after a deploy. no-cache does not mean do not store: it means store, but check with the server before each use, which a 304 answers cheaply.

map $uri $cache_control {
    default "";
    ~*\.html$   "no-cache";
}

The add_header inheritance trap

A location block that defines any add_header discards every add_header inherited from the server block. Adding Cache-Control in a location can therefore silently remove your HSTS and nosniff headers for those files. Repeat them in the location, or include a shared snippet.

Open the Caching & compression generator

Frequently asked questions

What is the difference between no-cache and no-store?

no-cache lets the browser store the response but forces revalidation before reuse. no-store forbids storing it at all, which you only need for sensitive responses.

Is it safe to use immutable on images?

Only if their file names change when their content does. Otherwise a replaced image stays stale in visitors' caches for the whole max-age.

Should I compress images and fonts too?

No. JPEG, PNG, WebP and WOFF2 are already compressed, so gzip adds CPU cost for almost no size saving. Compress text formats: HTML, CSS, JavaScript, JSON, SVG and XML.

Guides