ETag vs Last-Modified: Which Validator to Use
Choosing a validator is not cosmetic — it determines how precisely a cache can detect that a resource changed, how much CPU the origin spends answering revalidation requests, and what happens when both validators disagree. This guide walks through the decision with a comparison table and a decision flow, then shows how to confirm in practice which validator your server actually honors.
Prerequisite Concepts
- ETag Generation and Validation Strategies — how
ETagvalues are computed before you decide whether to rely on one. - Last-Modified and Date-Based Validation — the mechanics and limitations of the date-based validator on its own.
- Conditional Requests and 304 Responses — the shared request/response cycle both validators plug into.
Step-by-Step Resolution
Step 1 — Compare the two validators directly
| Dimension | ETag |
Last-Modified |
|---|---|---|
| Precision | Arbitrary — a content hash or version tag distinguishes any two distinct byte sequences | Capped at 1-second resolution (HTTP-date format has no sub-second component) |
| Compute cost | Higher if hashed per request; near-zero if precomputed at build/deploy time | Low — a single filesystem stat call, no body read required |
| Multi-server consistency | High, if derived from content or an application version column | Low, if derived from filesystem mtime that differs across cluster nodes |
| CDN / proxy handling | Forwarded verbatim unless the edge transforms the body (compression, minification) | Forwarded verbatim; largely immune to compression side effects since it’s a timestamp, not a body-derived value |
| Client conditional header | If-None-Match / If-Match |
If-Modified-Since / If-Unmodified-Since |
| Range request support | Only with a strong validator (see Strong vs Weak ETags Explained) | Not used for range validation at all — ranges rely on ETag/If-Range in practice |
| RFC precedence when both present | Wins — RFC 9110 §13.2.2 | Ignored if If-None-Match is also sent |
Step 2 — Apply the decision flow
In plain terms: reach for a content-hash ETag whenever precision matters or your origin runs on more than one node. Fall back to Last-Modified alone only for cheap, single-node, coarse-grained resources where a filesystem timestamp is good enough. When in doubt, emitting both costs little and maximizes compatibility.
Step 3 — Confirm the RFC 9110 precedence rule empirically
Capture both validators from a live resource:
curl -sI https://example.com/report.pdf | grep -iE 'etag|last-modified'
ETag: "b7c92f1e004a"
Last-Modified: Sun, 05 Jul 2026 18:00:00 GMT
Now send a request with a stale If-Modified-Since (a date before the resource last changed, which alone would force a 200 OK) but a matching If-None-Match:
curl -sI \
-H 'If-Modified-Since: Mon, 01 Jan 2024 00:00:00 GMT' \
-H 'If-None-Match: "b7c92f1e004a"' \
https://example.com/report.pdf
Expected result:
HTTP/1.1 304 Not Modified
The 304 proves the server evaluated If-None-Match and ignored the older, technically-failing If-Modified-Since — exactly the precedence RFC 9110 §13.2.2 mandates. If your server instead returns 200 OK here, it is not correctly prioritizing ETag, and you should treat Last-Modified on that platform as unreliable for combined use.
Step 4 — Verify CDN-level validator behavior
Different CDNs revalidate against different validators when their own edge TTL lapses. Check via response headers through the CDN versus direct to origin:
curl -sI https://example.com/report.pdf | grep -iE 'etag|last-modified|cf-cache-status|x-cache|age'
If the CDN dashboard or debug headers show revalidation requests reaching your origin with If-None-Match set, the edge is using ETag. Some CDNs default to whichever validator is present and prefer ETag when both exist, matching the RFC 9110 precedence rule; confirm the specific behavior for your provider rather than assuming it.
Expected Output / Verification
- A resource emitting both validators returns
304 Not Modifiedwhen a request supplies a correctIf-None-Match, even alongside a staleIf-Modified-Since— confirmingETagprecedence. Last-Modifiedalone correctly returns304whenIf-Modified-Sincematches or postdates the resource’s actual last-change time, and200 OKwith a fresh body otherwise.- CDN edge logs or debug headers show
If-None-Match(notIf-Modified-Since) in the upstream revalidation request whenever both validators were available at origin.
Edge Cases
- Sub-second updates collapse under Last-Modified — two writes to the same resource within the same second produce an identical
Last-Modifiedvalue, so a client relying solely on it will incorrectly treat the second version as unchanged. Only a content-hashETagdistinguishes them. - Clock skew degrades Last-Modified, not ETag — because
ETagcomparison is a pure string match independent of any clock, it is immune to the clock-skew failure modes that affect date-based validation; see Handling Clock Skew in Last-Modified Validation. - HTTP/1.1 vs HTTP/2 — the precedence rule and both conditional-header mechanisms are unaffected by transport version; the choice of validator is purely an application/origin-layer decision.
- Legacy intermediaries that only understand dates — some very old caching proxies only implement
If-Modified-Since. EmittingLast-ModifiedalongsideETagcosts almost nothing and preserves compatibility with that minority of clients without weakening the guarantees modern clients get fromETag.
Frequently Asked Questions
Which validator takes precedence when both ETag and Last-Modified are present?
ETag takes precedence. RFC 9110 Section 13.2.2 requires a server that supports If-None-Match to evaluate that condition and ignore If-Modified-Since whenever both are sent on the same request.
Is Last-Modified ever more accurate than ETag?
No. Last-Modified is capped at one-second granularity by its HTTP-date format, so it cannot express two distinct changes to a resource that occur within the same second. A content-hash ETag has no such limit.
Should I always emit both validators?
Yes, when the cost of computing an ETag is low. Emitting both maximizes compatibility with older or simpler clients and intermediaries that only implement date-based validation, while modern clients still get the precision of ETag.
Which validator is cheaper to compute for large files?
Last-Modified is cheaper because it only requires a filesystem stat call. A content-hash ETag requires reading the entire file, though this cost can be eliminated by computing the hash once at build or deploy time rather than per request.
Related
- Last-Modified and Date-Based Validation — the full mechanics of date-based validation covered on its own terms.
- Strong vs Weak ETags Explained — the comparison-function nuances that matter once you’ve chosen
ETag. - How to Debug 304 Not Modified Responses — troubleshooting steps when neither validator produces the expected status code.