HTTP entity tags come in a strong form like "abc" and a weak form written W/"abc". As an API designer, when would you deliberately issue a weak ETag, and what do you give up by doing so?
answer
- strong = same bytes; weak = same meaning
- W/ prefix is syntax, not part of the value
- If-None-Match = weak comparison (304s still work)
- If-Match and If-Range = strong comparison
- weak tag → no optimistic concurrency, no ranges
basics
~20 sA strong ETag promises byte-for-byte identical content; a weak one promises only semantic equivalence. Issue weak tags when the bytes may vary harmlessly (compression, field ordering, cosmetic fields) but the meaning does not. You give up range requests and optimistic-concurrency preconditions, which need strong comparison.
solid answer
~50 s**Strong** `ETag: "abc"` asserts that two representations with the same tag are byte-for-byte identical. **Weak** `ETag: W/"abc"` asserts only that they are *semantically equivalent* — a client may substitute one for the other without a meaningful difference. Issue weak tags when your pipeline cannot guarantee byte stability but the payload's meaning is stable: responses recompressed or reserialized by an intermediary, JSON whose field order or numeric formatting is not deterministic across instances, or bodies that embed a cosmetic element you do not want to count as a change. What you give up: HTTP evaluates preconditions with **strong comparison** for anything that depends on exact bytes. `If-Range` will not accept a weak tag, so range requests and resumable downloads degrade to full transfers. `If-Match` — the optimistic-concurrency guard against lost updates — also uses strong comparison, so weak tags cannot protect writes. Revalidation still works: `If-None-Match` uses weak comparison, so weak tags produce 304s normally.
code
http · 12 linesHTTP/1.1 200 OK
ETag: W/"v7"
GET /v1/docs/9 HTTP/1.1
If-None-Match: W/"v7"
HTTP/1.1 304 Not Modified
PUT /v1/docs/9 HTTP/1.1
If-Match: W/"v7"
HTTP/1.1 412 Precondition Failedgo deeper
Know that W/ marks a weak tag meaning 'semantically the same', while a plain quoted tag means byte-identical.
Explain which conditional headers use weak versus strong comparison, and that 304s still work with weak tags.
Justify the choice from your serialization pipeline and state the concurrency and range-request consequences explicitly.
Set an organisation-wide default — deterministic serialization plus strong tags from version columns — and treat weak tags as a documented exception with an alternative concurrency contract.
## The two comparison functions An entity tag identifies a specific version of a representation. HTTP defines two ways to compare tags: - **Strong comparison**: the tags match only if both are strong and their opaque values are identical. - **Weak comparison**: the tags match if their values are identical, regardless of whether either carries the `W/` prefix. The prefix is a claim about the *strength of the promise*. A strong tag says: if you see this tag again, the octets are identical. A weak tag says: if you see this tag again, the representation means the same thing, but the bytes might differ. Which comparison is used depends on the header field: - `If-None-Match` (revalidation on GET) → **weak comparison**. Weak tags work fine. - `If-Match` (preconditions on writes) → **strong comparison**. Weak tags never match, so the precondition fails with 412 forever. - `If-Range` (conditional range request) → **strong comparison**. A weak tag is unusable, so the client must refetch the whole thing. That asymmetry is the entire design tradeoff. Weak tags buy revalidation robustness at the cost of everything that needs byte identity. ## When weak is the honest choice **Byte instability you cannot remove.** JSON serializers that do not guarantee key order, floating point formatted differently across runtimes or locales, maps iterated non-deterministically, or a payload assembled from several services whose whitespace differs. If two servers behind a load balancer can emit different bytes for the same logical state, a strong tag is a lie — and the practical symptom is a client bouncing between validators and never getting a 304. **Transformations in the path.** Content coding applied or removed by a proxy, minification, or an edge that injects a header-driven variant. If the origin's tag survives a transformation that changes bytes, it must be weak. **Deliberately ignoring cosmetic change.** Suppose a resource embeds a computed "popularity" figure or a rendered timestamp that changes constantly but that no client acts on. Rather than churning the validator every second, you can issue a weak tag over the meaningful fields only, saying "any of these variants is equivalent for your purposes". This is a genuine contract decision, and it must be documented — a client that needs to see that field change will be silently starved of updates. ## What you sacrifice **Optimistic concurrency.** The lost-update guard is: client reads a resource, gets `ETag: "v7"`, sends `PUT` with `If-Match: "v7"`, and the server rejects with `412 Precondition Failed` if someone else has written meanwhile. Because `If-Match` uses strong comparison, a weak tag can never satisfy it. If your resource is mutable and you want safe concurrent editing, it needs a strong tag — which in turn means you need a deterministic version source, typically a row version column rather than a body hash. **Range requests.** Resumable downloads and byte-range fetches use `If-Range` to confirm the client's partial copy still matches. A weak tag forces a full re-download. For large binary resources served through an API, that is a real regression. ## The practical recipe Prefer strong tags derived from a version column, and make serialization deterministic so the promise is true — canonical key order, fixed numeric formatting, stable array ordering. That gives you revalidation *and* concurrency *and* ranges from one mechanism. Fall back to weak tags when determinism is genuinely out of reach, or when you consciously want the validator to ignore cosmetic churn. Then document that writes to those resources use a different concurrency mechanism — a version field in the request body, or a separate strong version token — because the ETag will not carry that weight. One last correctness note: `W/` is part of the field value's syntax, not part of the opaque tag. Servers that store the literal string `W/"abc"` as "the version" and compare it with naive string equality break both comparison rules; parse the prefix and the quoted value properly, and remember the quotes are mandatory in the header value.
- Your API uses weak ETags but you now need to prevent lost updates. What changes?You need a strong validator, because If-Match is evaluated with strong comparison and a weak tag can never satisfy it. That usually means deriving the ETag from a deterministic version source such as a row version column and making serialization canonical, or introducing an explicit version field carried in the request body as the concurrency token instead.
- Does a weak ETag still produce 304 responses?Yes. If-None-Match uses weak comparison, so a weak tag matches its own value and revalidation works exactly as with a strong tag. That is precisely why weak tags are useful: you keep the revalidation benefit while being honest that the bytes may differ.
A strong ETag is a photocopy checksum — identical down to the ink. A weak ETag is 'same edition, possibly a different printing': fine for deciding whether to reread it, useless for proving nobody amended the page you are about to overwrite.
saying these in an interview costs you the question
- Believing weak ETags disable caching or 304 responses
- Using weak ETags for optimistic concurrency and being puzzled by permanent 412s
- Treating the W/ prefix as part of the opaque tag value in string comparisons
- Emitting strong ETags from a non-deterministic serializer, so identical state yields different tags
- Assuming weak versus strong is a performance setting rather than a correctness claim