Definition
This is an HTTP feature used to avoid downloading the entire body every time you fetch the same data repeatedly. When the server attaches a hash (or version) of the response body via the ETag header, the client sends If-None-Match: <etag> on the next request to ask "is this still the same?" If the content is unchanged, the server returns just 304 Not Modified with no body, and the client reuses the cached copy it already has.
An ETag is a short string tag that identifies a specific version of a resource, and a conditional request is a request that says "only give me the body if the condition holds."
Why It's Needed
The symptom: users frequently re-request read responses like lists and detail views, and even when the content hasn't changed, several KB to tens of KB of JSON gets downloaded again in full every time. On mobile and high-traffic scenarios, this is wasteful.
ETag/304 asks only "did it change?" and drives download bytes to zero when nothing changed. But there's a limit you must understand. Even to return a 304, the server still has to query, serialize, and compute the hash every time, so ETag saves only network transfer, not server compute. To cut the server's work too, you need a separate mechanism that judges "unchanged" up front using a cheap indicator, before building the body.
How It Works
- body-hash ETag: hash the response body into the tag. Simple to implement, but the server must build the full body every time (transfer savings only).
- strong vs weak:
"abc"means byte-for-byte identical;W/"abc"means semantically equivalent. For a negotiation cache, weak is usually sufficient. - cheap validator: to save server compute too, first query a cheap indicator like
max(updated_at) + count; if it matches, skip generating the body entirely.
Practical Application
The version that also saves server compute queries the validator first with SELECT max(updated_at), count(*) before loadItems(); if it matches, it skips loadItems() and returns 304.
Trade-offs
- What you gain: zero download bytes on revisits with no change. Combined with a client cache, it feels fast.
- What you don't gain: with the body-hash approach, the server query and serialization cost remains unchanged.
- Over-investment risk: if the page is already covered by an ISR/CDN static cache for its body, the gain from a separate ETag layer is small. Look at that route's caching strategy first before adopting it.
When Not to Use It
- Resources whose content changes on every request (real-time feeds) — 304 almost never fires, so it's pointless.
- Routes where a static/ISR cache already covers the body — the ETag layer is a duplicate investment.
- Cases where the response is so small that the transfer savings are negligible.
Common Mistakes
- Assuming ETag also saves server compute (it saves only bandwidth).
- Mixing values that differ on every request (timestamps, etc.) into the body, so the ETag always changes and 304 never fires.
- Not distinguishing strong/weak, causing conflicts with proxies and compression.
- Using only body-hash without a validator while expecting "server load will drop."
Related Concepts
- service-worker-stale-while-revalidate — combining with a client-side cache layer
- cache-generation-stale-write-guard — preventing stale writes via cache generation/invalidation