Glossary

ETag

An `ETag` is an opaque string a server attaches to a response to identify that specific version of the resource. When a cached copy expires, the client sends the tag back in an `If-None-Match` request header, and the server answers `304 Not Modified` with no body if nothing has changed. It turns an expensive re-download into a cheap round trip, and it is the mechanism that makes short cache lifetimes affordable.

How revalidation works

The server sends `ETag: "abc123"` with the response, and the client stores it alongside the cached body.

When the cached copy is no longer fresh, the client repeats the request with `If-None-Match: "abc123"`.

If the resource still has that tag, the server answers `304 Not Modified` with headers only. The client keeps its copy and resets its freshness.

If it has changed, the server answers `200` with the new body and a new tag.

`Last-Modified` and `If-Modified-Since` do the same job with a timestamp, at one-second resolution. Both may be sent, and `ETag` takes precedence.

Strong and weak tags

A strong tag asserts the bytes are identical. It is required for range requests, where the client asks for part of a resource it already partly has.

A weak tag, prefixed `W/`, asserts the representations are equivalent for practical purposes even if the bytes differ — the same content with a different compression, for example.

Weak tags are appropriate for dynamically generated responses, where an exact byte match is neither achievable nor meaningful.

Choosing weak where strong is needed breaks range requests, which matters for video seeking and resumable downloads.

Why they break behind multiple servers

Some web servers derive the tag from filesystem metadata including the inode number, which differs between machines serving identical files.

The result is that a client revalidating against a different server than it originally fetched from receives a different tag and a full 200 response, so revalidation never succeeds.

The symptom is repeated full downloads of unchanged files, visible as high bandwidth with no 304 responses.

The fix is to derive the tag from the content — a hash — or to disable ETags and rely on `Last-Modified`, which is consistent across machines.

How to check it

`curl -I https://example.com/asset.js` shows the tag. Repeating with `-H 'If-None-Match: "<tag>"'` should return `304`.

If the second request returns `200`, revalidation is not working and the reason is usually the multi-server case above.

In the browser's network panel, a working setup shows `304` responses with a size of a few hundred bytes on reload.

For versioned static assets with a year-long immutable policy, ETags are largely irrelevant: those URLs are never revalidated at all, which is the intended behaviour.

Frequently asked questions

What is the difference between ETag and Last-Modified?
ETag is an opaque version identifier; Last-Modified is a timestamp with one-second resolution. Both enable revalidation, and ETag takes precedence when both are present.
Should I disable ETags?
Only if they are generated inconsistently across servers, which defeats revalidation. A content-derived tag is better than none.
What does a weak ETag mean?
The representations are equivalent for practical purposes even if the bytes differ. Strong tags are required for range requests.

Sources

Related

VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.

Scan a website