HTTP 304 Not Modified

Quick answer

HTTP 304 Not Modified means your cached copy of the resource is still valid, so the server returns no body. It is sent in response to a conditional request.

What HTTP 304 means

304 Not Modified is part of HTTP caching. When a client sends a conditional request with If-None-Match (an ETag) or If-Modified-Since, and the resource has not changed, the server responds 304 with no body. The client then uses its cached copy, saving bandwidth.

Common causes

Response body

A 304 has no body — the client reuses its cached copy. Do not parse a response body on a 304.

Raw HTTP response

HTTP/1.1 304 Not Modified
ETag: "a1b2c3d4"
Cache-Control: max-age=3600

How to handle HTTP 304

How conditional requests produce a 304

A 304 is the second half of a two-step caching conversation. First, the server hands the client a validator on the original 200 response. Later, the client sends that validator back, and the server decides whether anything changed:

# 1) First response includes a validator
HTTP/1.1 200 OK
ETag: "a1b2c3d4"

# 2) Client re-requests with the validator
GET /api/data HTTP/1.1
If-None-Match: "a1b2c3d4"

# 3) Unchanged → server saves bandwidth
HTTP/1.1 304 Not Modified

ETag vs Last-Modified

There are two validator mechanisms, and they pair up:

Server sendsClient echoesBased on
ETag: "a1b2c3d4"If-None-MatchA content hash/version — precise to the byte
Last-Modified: <date>If-Modified-SinceA timestamp — 1-second resolution

Prefer ETag when you can compute one cheaply — it catches changes that share the same timestamp and avoids the 1-second granularity limit of Last-Modified.

Handling 304 in client code

Browsers handle 304 transparently — your fetch sees a 200 with the cached body, not a 304, because the cache layer resolves it. You typically only observe a raw 304 when you manage caching yourself (a CDN, an HTTP library with manual revalidation, or a server-to-server client storing ETags). In that case: on 304, reuse the stored body; on 200, replace your cache and store the new ETag.

Frequently Asked Questions

Why does a 304 have no body?

Because the client already has a valid cached copy. The whole point of 304 is to save bandwidth by telling the client "nothing changed, use what you have" instead of resending the resource.

What triggers a 304 response?

A conditional request: the client sends If-None-Match with an ETag, or If-Modified-Since with a date. If the resource has not changed, the server replies 304 instead of 200 with the full body.

Is 304 an error?

No. 304 is a normal, successful part of HTTP caching. It means the cached version is still good.

What is the difference between ETag and Last-Modified?

An ETag is a content version identifier (often a hash), echoed back via If-None-Match — precise to the byte. Last-Modified is a timestamp, echoed via If-Modified-Since — limited to 1-second resolution. ETag is more accurate; use it when you can generate one cheaply.

Why don't I ever see a 304 in my fetch code?

Because the browser's HTTP cache resolves it for you — your fetch receives a 200 with the cached body. You only observe raw 304s when you manage caching manually, such as in a CDN, a server-to-server client, or an HTTP library configured for manual revalidation.

Working with a JSON API response?

Format and inspect any response in your browser — nothing is uploaded.

JSON Formatter JSON Validator All HTTP Status Codes
About the author

Pasindu Ishan is a software developer based in Sri Lanka. He builds privacy-first developer tools at JSON Dev Tools.