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.