If-None-Match
request headercaching
Makes a request conditional: send the resource only if its current ETag isn't one of those listed.
If-None-Match carries the ETag or ETags a client already has. For GET and HEAD, the server answers 304 Not Modified if the current ETag matches, so the client can reuse its copy. With the value *, it means 'only if no version exists yet' — a way to create something without overwriting what's there.
Syntax
If-None-Match: "<etag>", "<etag>"… or If-None-Match: *
Defined in RFC 9110 §13.1.2 — If-None-Match.
Examples
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
revalidate a cached copy
If-None-Match: *
on a PUT: create the resource only if it doesn't exist
Good to know
- Browsers send it automatically when revalidating; you only set it by hand in API clients.
- When a request carries both,
If-None-Matchtakes precedence overIf-Modified-Since. - With
*on a write, an existing resource produces 412 Precondition Failed.
Who sets If-None-Match
Browsers send If-None-Match on their own when they revalidate a cached response that had an ETag. To test revalidation, copy the ETag from a response and send it back: curl -sI -H 'If-None-Match: "33a64df5"' https://example.com/app.css — a matching ETag returns 304.
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
Why does fetch() never show me a 304?
The browser revalidates its own cache and hands your code the cached 200. You only see the 304 if you add If-None-Match yourself.