Back to HTTP Headers

If-Unmodified-Since conditional request

Makes a request conditional on a resource NOT having changed since a given timestamp — the date-based counterpart to If-Match.

What it does

If-Unmodified-Since makes a request — typically a write (PUT, PATCH, DELETE) — conditional on the resource not having been modified since a given timestamp. It's the timestamp-based counterpart to If-Match: both exist to prevent the lost-update problem (two clients editing the same resource, the second write silently clobbering the first), but If-Match uses an ETag while If-Unmodified-Since uses a Last-Modified date.

If the resource has changed since the supplied timestamp, the server rejects the request with 412 Precondition Failed rather than applying the write over a version the client hasn't actually seen.

Syntax

If-Unmodified-Since: <HTTP-date>

Sent with a previously-received Last-Modified value:

If-Unmodified-Since: Wed, 21 Oct 2015 07:28:00 GMT

Commonly paired with PUT, PATCH, or DELETE requests — using it on a plain GET is unusual, since If-Modified-Since (the inverse condition) is what GET requests typically want for cache revalidation.

Preventing lost updates with timestamps

GET /articles/42 HTTP/1.1

HTTP/1.1 200 OK
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
Content-Type: application/json

{"title": "Draft"}

Client edits, then submits with the timestamp it saw:

PUT /articles/42 HTTP/1.1
If-Unmodified-Since: Wed, 21 Oct 2015 07:28:00 GMT
Content-Type: application/json

{"title": "Final"}

Unchanged since — write succeeds:

HTTP/1.1 200 OK
Last-Modified: Sun, 16 Aug 2026 14:20:00 GMT

Modified by someone else in the meantime — write rejected:

HTTP/1.1 412 Precondition Failed

Why If-Match is usually preferred

Same underlying trade-off as If-Modified-Since vs. If-None-Match on the read side:

  • Timestamp resolution. Modification times typically only have one-second granularity — two different writes within the same second are indistinguishable, meaning If-Unmodified-Since could let a genuinely conflicting write through that If-Match's content-hash comparison would have caught.
  • Identical re-saves still bump the timestamp. A resource re-saved with unchanged content still updates Last-Modified, which could cause If-Unmodified-Since to reject a write that would have been perfectly safe under ETag-based comparison.
  • No dependency on ETag support. Its real advantage: it works purely off Last-Modified, which is cheap for a server to track (usually just a filesystem or database timestamp) even when the server doesn't generate ETags at all — making it a reasonable fallback for simpler systems.

Common mistakes and gotchas

Using it interchangeably with If-Modified-Since. They're opposite conditions on opposite methods, easy to mix up given the similar names — If-Unmodified-Since protects writes (proceeds if unchanged), If-Modified-Since drives cache revalidation on reads (proceeds if changed). Using one where the other belongs inverts your intended logic entirely.

Relying on it for high-frequency concurrent writes. Given the one-second timestamp resolution, resources that can be modified multiple times per second aren't safely protected by this header alone — If-Match with a content-based ETag is the more reliable choice for genuinely concurrency-sensitive resources.

Forgetting the server needs to actually implement the check. Sending Last-Modified on GET responses doesn't automatically mean the server validates If-Unmodified-Since on write requests — that enforcement has to be explicitly implemented server-side for the protection to actually exist.

Date format mistakes. Same as If-Modified-Since — HTTP dates require an exact format (always GMT, always the specific structure). A malformed value is typically silently ignored rather than erroring, quietly disabling the protection.

Real-world examples

Successful protected update:

PATCH /api/tickets/5521 HTTP/1.1
If-Unmodified-Since: Sat, 15 Aug 2026 09:00:00 GMT
Content-Type: application/json

{"status": "resolved"}

HTTP/1.1 200 OK
Last-Modified: Sun, 16 Aug 2026 11:45:00 GMT

Rejected due to a change since the client's last read:

PATCH /api/tickets/5521 HTTP/1.1
If-Unmodified-Since: Sat, 15 Aug 2026 09:00:00 GMT
Content-Type: application/json

{"status": "resolved"}

HTTP/1.1 412 Precondition Failed

FAQ

What's the difference between If-Unmodified-Since and If-Match?

Both protect against lost updates, but If-Match compares ETags (content-based, more precise) while If-Unmodified-Since compares timestamps (coarser resolution, but works without ETag support). Prefer If-Match when the server generates ETags; If-Unmodified-Since is a reasonable fallback otherwise.

What status code does a failed check return?

412 Precondition Failed — same as a failed If-Match — the write is rejected before being applied, signaling to the client that its view of the resource is stale and it should re-fetch before retrying.

Can If-Unmodified-Since be used on GET requests?

It's technically valid, but unusual — GET requests wanting conditional caching behavior should use If-Modified-Since (the inverse condition) instead. If-Unmodified-Since on a GET has a defined but rarely-used meaning (return the resource only if unchanged, otherwise 412), distinct from the far more common revalidation pattern.

Is it safe to rely on If-Unmodified-Since alone for concurrency-critical resources?

Not fully — the one-second timestamp resolution means two conflicting writes within the same second can't be distinguished. For anything where concurrent-write conflicts are a real, frequent risk, If-Match with a proper content-based ETag gives a stronger guarantee.

Fun fact

If-Unmodified-Since is a good example of how HTTP's conditional-request headers were built up incrementally in pairs — for essentially every read-side conditional check (If-Modified-Since), there's a corresponding write-side one (If-Unmodified-Since), and the same pairing exists between If-None-Match and If-Match. This symmetry wasn't an accident: the spec authors designed cache revalidation and concurrency control as mirror-image problems solved by the same two validator types (ETag and Last-Modified), just applied with inverted logic depending on whether you're reading or writing.