devkult_
tools29converters34
home/headers/if-match

If-Match

request headercaching

Makes a write conditional: apply it only if the resource still has this ETag. Prevents lost updates.

Two people load the same document, both edit, both save — and the second save silently overwrites the first. If-Match prevents that: the client sends back the ETag it read, and the server applies the change only if the current ETag still matches. Otherwise it answers 412 Precondition Failed, and the client can reload and merge.

Syntax

If-Match: "<etag>"[, "<etag>"…]   or   If-Match: *

Defined in RFC 9110 §13.1.1 — If-Match.

Values

"<etag>"proceed only if the current version has this ETag
*proceed only if the resource exists — never create it

Examples

If-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

update only the version I read

If-Match: *

update only if it already exists

Good to know

  • If-Match uses strong comparison, so weak ETags (W/"…") never match.
  • APIs can require it: answer 428 Precondition Required when a write arrives without one.
  • If-None-Match: * is the opposite guard — create only if nothing exists yet.
  • Cross-origin clients can only read the ETag they need if it's listed in Access-Control-Expose-Headers.

Using If-Match for safe updates

Client (fetch)
const res = await fetch("/api/docs/42");
const etag = res.headers.get("ETag");
const doc = await res.json();

const save = await fetch("/api/docs/42", {
  method: "PUT",
  headers: { "Content-Type": "application/json", "If-Match": etag },
  body: JSON.stringify({ ...doc, title: "New title" }),
});
if (save.status === 412) {
  // Someone else changed it first: reload and merge
}
Server (Express)
app.put("/api/docs/:id", async (req, res) => {
  const doc = await db.get(req.params.id);
  const current = `"${doc.version}"`;
  const ifMatch = req.get("If-Match");
  if (!ifMatch) return res.status(428).json({ error: "If-Match required" });
  if (ifMatch !== "*" && !ifMatch.split(/\s*,\s*/).includes(current)) {
    return res.status(412).json({ error: "Document has changed" });
  }
  // ...apply the update and send the new ETag
});

Check it

In the browser, open DevTools → Network, pick a request and look under Request Headers. From the command line, curl's verbose mode prints every header it sends, prefixed with >:

curl -sv https://example.com/ -o /dev/null 2>&1 | grep '^>'

Frequently asked questions

What's the difference between If-Match and If-None-Match?

If-Match proceeds only when the ETag matches, which guards writes. If-None-Match proceeds only when it doesn't, which drives cache revalidation (304) and, with *, create-only requests.

Status codes it appears with
Related headers