If-Modified-Since header: format, example and nginx's exact-match default (tested)

If-Modified-Since sends back a date; if the file hasn't changed since then, the server answers 304 Not Modified with no body. We tested which dates nginx accepts.

1. Format and example

If-Modified-Since: Thu, 01 Oct 2026 10:00:00 GMT

$ curl -sI -H 'If-Modified-Since: Thu, 01 Oct 2026 10:00:00 GMT' https://site/a.txt
HTTP/1.1 304 Not Modified

$ curl -sI -z 'Thu, 01 Oct 2026 10:00:00 GMT' https://site/a.txt   # curl's shortcut
HTTP/1.1 304 Not Modified

Always GMT, in the same format as the server's Last-Modified. Browsers simply echo the Last-Modified value they received, which is the safest choice.

2. What nginx answered (file Last-Modified 10:00:00 GMT)

If-Modified-Sincedefault (exact)if_modified_since before;
10:00:00 (same as Last-Modified)304304
11:00:00 (later)200304
09:00:00 (earlier: file changed since)200200
Thursday, 01-Oct-26 10:00:00 GMT (old RFC 850 form)304304
garbage200200

The surprise is row 2: by default nginx only returns 304 when the date matches Last-Modified exactly. A client that sends "now" or its own download time gets the full file every time. Either send back the server's Last-Modified verbatim, or set if_modified_since before; in nginx to get the textbook "not modified since" behaviour.

3. ETag wins

With the exact matching date and If-None-Match: "x" (a wrong ETag), nginx answered 200: when both are sent, the ETag check decides. Clients that store both should send both; servers use the ETag (how nginx builds ETags).

4. When it is used

Browsers send If-Modified-Since when revalidating a cached file that has Cache-Control: no-cache, an expired max-age, or no caching headers. Which Cache-Control values trigger a revalidation was measured separately.

Frequently asked questions

What is the format of If-Modified-Since?

An HTTP date in GMT, e.g. Thu, 01 Oct 2026 10:00:00 GMT. nginx also accepted the old form Thursday, 01-Oct-26 10:00:00 GMT; an invalid date got a normal 200.

Why does nginx return 200 instead of 304 for If-Modified-Since?

nginx's default if_modified_since exact only answers 304 when the date equals Last-Modified. A later date got 200 in our test; 'if_modified_since before;' changes that.

If-Modified-Since or If-None-Match?

If both are sent, the ETag decides: a wrong If-None-Match gave 200 although the date matched.

How do I send If-Modified-Since with curl?

curl -H 'If-Modified-Since: <date>' URL, or curl -z '<date>' URL. Both got 304 for the exact Last-Modified date.

Written with AI assistance. Measured on 2026-10-01 with curl 8.14.1 against nginx 1.31.6 (nginx:alpine, throwaway container) serving a file whose Last-Modified was Thu, 01 Oct 2026 10:00:00 GMT, with the default if_modified_since setting and with 'if_modified_since before'. When browsers send the header (section 4) is from the HTTP spec, not this test. PlainHeaders is our extension; curl is free.