API design
Optimistic concurrency with ETags: interview questions and practical design
Optimistic concurrency with ETags prevents a client from overwriting a newer representation by requiring its update to match the version it read.
Written and reviewed by Sahil Srivastav
What it actually is
Optimistic concurrency with ETags prevents a client from overwriting a newer representation by requiring its update to match the version it read.
Two editors can read the same document and submit different changes. Without a precondition, the later write silently erases the earlier one.
The useful interview answer is precise about the boundary: The server returns an ETag representing the exact version or representation. A client sends `If-Match` on a mutation; the server updates only when the tag still matches.
Why it matters in production
Two editors can read the same document and submit different changes. Without a precondition, the later write silently erases the earlier one.
ETags move the version check into HTTP’s conditional request semantics, where caches and clients already understand it.
How it works
Representation validator
The server returns an ETag representing the exact version or representation. A client sends `If-Match` on a mutation; the server updates only when the tag still matches.
412 versus 409
A failed `If-Match` precondition is commonly 412 because the request condition is false. Use 409 when the domain operation conflicts for a reason beyond a conditional validator.
Strong and weak validators
A strong ETag supports byte-sensitive update safety; a weak validator can express semantic equivalence for caching but is not appropriate when every representation difference matters.
Implementing it
Add a version column and conditional update to one resource.
Run two clients from the same initial ETag and verify one receives a precondition failure.
Return the current representation or a safe refresh hint without applying the stale update.
Interview questions and how to answer them
Why is an ETag better than a last-updated timestamp?
It is an explicit validator with well-defined conditional semantics and can represent a version even when timestamps collide or clocks differ.
How do you implement the check safely?
Include the version predicate in the update, check affected rows, and return a precondition failure when no row matched. A prior read check is not enough.
What should the client do after 412?
Fetch or merge the current representation, present the conflict if necessary, then retry with a fresh ETag. Do not blindly replay the stale body.
Answers that lose the round
- Checking the ETag in application code and writing later without an atomic predicate.
- Using a timestamp with insufficient precision as the only version.
- Treating 412 as a server error and retrying the stale mutation unchanged.
- Using weak ETags for a write precondition that needs exact version identity.
FAQ
Are ETags only for caching?
No. They are validators for both cache revalidation and optimistic write concurrency.
Can an ETag be a database version number?
Yes, if it changes on every relevant representation update and is scoped to the resource. Do not expose a mutable value that can be forged if that matters.
Does this prevent all lost updates?
It prevents updates that honour the precondition from overwriting a newer version. Clients and all write paths must participate for the guarantee to hold.