caching

ETag

An opaque identifier for a specific version of a resource, used by clients in conditional requests to avoid re-downloading unchanged bodies. The server compares the ETag against If-None-Match (or If-Match) and returns 304 Not Modified when they match.

ETag: [W/]"<opaque-validator>"  (strong: "33a64df551", weak: W/"33a64df551")

Common directives / values

Directive Purpose
"<hash>" Strong validator — byte-for-byte identical representation.
W/"<hash>" Weak validator — semantically equivalent, but bytes may differ (e.g. after gzip).
content-hash form Commonly SHA-1/MD5 of body, base64 or hex, quoted.
version+mtime form Composite tag like "v3-1737000000" combining app version and mtime.

Examples

ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

Strong ETag returned with 200 OK; client stores and echoes on next request.

ETag: W/"5-x1y2z3"

Weak ETag suitable for responses that are gzipped or minor-normalized.

HTTP/1.1 304 Not Modified\nETag: "33a64df551"

Server response when the client's If-None-Match matches — no body sent.

ETag: "deadbeef"\nCache-Control: no-cache

Combined pattern: browser stores response but must revalidate via ETag before reuse.

Gotcha

Nginx REMOVES the ETag entirely when applying on-the-fly gzip (ngx_http_clear_etag), so downstream conditional requests and Range requests lose the validator. Precompress with gzip_static (or set the ETag from upstream in a way that survives the filter) if you need to preserve ETags on gzipped responses.

Related headers

← All HTTP headers · HTTP status codes · Fix CORS errors