Skip to content
Devgo

ETag / conditional requests

A header giving a resource a version fingerprint; clients send it back to check if it changed (304 Not Modified) or to avoid concurrent overwrites (If-Match). Saves bandwidth and enables optimistic concurrency. Built into HTTP.

When to use
  • Caching and revalidation (304s).
  • Optimistic concurrency on writes (If-Match).
When not to
  • Resources that change every request (no caching benefit).
  • When you need server-side locking instead.

Definition

An ETag is a hash/version of a representation. GET with If-None-Match returns 304 if unchanged (no body). PUT with If-Match only succeeds if the ETag matches, preventing lost updates. Weak ETags are semantically equal, strong byte-equal.

Why it exists

Re-downloading unchanged resources wastes bandwidth; overwriting based on stale reads loses updates. ETags make caching and optimistic concurrency cheap and standard.

How it works

Server computes an ETag (hash of content/version). Client caches it. On revalidate, sends If-None-Match; server returns 304 if it matches. On write, sends If-Match: "etag"; server rejects (412) if someone else changed it. CDNs use ETags for revalidation.

Scaling limits

ETag computation adds CPU. Strong ETags break under content-encoding differences. Conditional writes need the client to have fetched the current ETag first.

Cost shape

Negligible. Saves bandwidth and prevents lost updates. Blow-ups: expensive ETag computation per request.

Alternatives

  • Last-Modified — Coarser time-based revalidation.
  • Version field in payload — Same idea, app-level, not -standard.

Failure modes

  • Weak vs strong ETag confusion.
  • ETag not varying with content (stale 304s).
  • Hash collisions in weak schemes.

, ,