304 Not Modified
3xx redirection
The cached copy is still valid; use it instead of downloading the resource again.
304 is the payoff of conditional requests. When a browser holds a cached response with an ETag or Last-Modified, it revalidates with If-None-Match or If-Modified-Since. If nothing changed, the server answers 304 with no body and the browser reuses its copy — a few hundred bytes instead of the full file.
| Class | 3xx Redirection |
|---|---|
| Retry? | Not applicable |
| Cacheable by default | No — only with explicit Cache-Control |
| Response body | None |
| Defined in | RFC 9110 §15.4.5 — 304 Not Modified |
HTTP/1.1 304 Not Modified
When you'll see it
- Revalidation of a cached page, image or API response.
- Reloading a page, which makes the browser revalidate its cache.
How to use it well
- Send
ETagorLast-Modifiedon cacheable responses so clients can revalidate. - Never include a body in a 304.
- Stale content after a deploy means the server is wrongly answering 304, usually because the ETag doesn't change with the content. Fingerprint asset URLs (
app.3f2a1c.js) and cache them as immutable instead.
Useful here: HTTP caching explained
Check what a URL returns
Print just the status line from the command line, or check a whole list of URLs at once, with their response headers, in the HTTP Status Checker.
curl -sI https://example.com/your-path | head -n 1
Frequently asked questions
Is a 304 an error?
No — it's the best case for a cached resource. In DevTools it shows up as a request that transferred only headers.
Why does fetch() show 200 when the server sent 304?
The browser handles revalidation itself and hands your code the cached 200 response. You only see a 304 if you send the conditional headers yourself.