HTTP 304 Not Modified

HTTP 304 Not Modified indicates the resource has not changed since the version identified by the conditional headers (If-Modified-Since or If-None-Match). The server returns no body, telling the client to use its cached copy. This is the foundation of HTTP caching validation — it lets the server confirm the client's cache is still fresh without retransmitting the resource, saving bandwidth and improving load times.

Debug HTTP 304 live
Analyze real 304 behavior — headers, caching, CORS, redirects
Open Inspector →

Try it (live endpoint)

Response includes the status code, standard headers (including Content-Type), and a small diagnostic JSON body describing the request and returned status.

Simulator URL (copy in the app after load — not a normal link):

https://httpstatus.com/api/status/304

Example request:

curl -i "https://httpstatus.com/api/status/304"
Try in playground

Meaning

Indicates that the resource has not been modified since the version specified by the request headers (If-None-Match or If-Modified-Since). The client should use its cached copy.

What it guarantees
  • A different URI is involved to complete the intent.
  • The representation has not changed since the client’s validator.
What it does NOT guarantee
  • All clients will automatically follow the redirect.
  • The redirect target is safe to cache unless headers allow it.
  • A client will receive a response body.

When to use this status

  • GET is conditional (If-None-Match / If-Modified-Since) and content is unchanged.
  • CDN/origin revalidation where cached content remains valid.
  • Bandwidth-sensitive clients using validators for large representations.

When NOT to use this status (common misuses)

Redirecting without a stable Location target.
Clients fail to follow; crawlers lose canonical signals.
Using 301/302 for non-GET methods without understanding method rewriting.
Clients can drop bodies or change methods, causing data loss and client bugs.
Redirect loops or long chains.
Crawlers waste crawl budget; clients hang; retries amplify load.
Returning a body with 304 or changing validators incorrectly.
Caches become inconsistent; clients may serve stale or corrupted content.

Critical headers that matter

Location
Tells clients where to go next.
Redirects fail or loop; crawlers lose canonical target.
Cache-Control
Controls whether redirects are cached.
Temporary redirects become sticky; permanent redirects never stick.
Vary
Prevents caches mixing redirect variants.
CDNs serve the wrong redirect for different hosts/headers.
ETag / Last-Modified
Validators must align with cached representation.
Caches serve stale or inconsistent content.

Tool interpretation

Browsers
Follows Location for navigations; redirect caching can make behavior sticky. Redirect code choice affects method/body handling.
API clients
May not auto-follow; strict clients require explicit redirect handling. Incorrect redirect semantics can drop bodies or change methods.
Crawlers / SEO tools
Uses redirects for canonicalization; long chains/loops waste crawl budget and dilute signals.
Uptime monitors
Typically marks success; advanced checks may flag header anomalies or latency.
CDNs / reverse proxies
Can cache redirects; Location/Vary/Cache-Control correctness drives global consistency.

Inspector preview (read-only)

On this code, Inspector focuses on semantics, headers, and correctness warnings that commonly affect clients and caches.

Signals it will highlight
  • Status semantics vs method and body expectations
  • Header sanity (Content-Type, Cache-Control, Vary) and evidence completeness
  • Redirect chain length, loops, Location presence, protocol safety
Correctness warnings
  • Body present with 304 is incorrect; validators must match cached representation.

Guided Lab outcome

  • Reproduce HTTP 304 Not Modified using a controlled endpoint and capture the full exchange.
  • Practice distinguishing status semantics from transport issues (redirects, caching, proxies).
  • Validate redirect correctness (Location, hop count, protocol safety) and SEO impact.

Technical deep dive

304 Not Modified (RFC 7232 Section 4.1) is triggered by conditional requests: the client sends If-None-Match: "etag-value" or If-Modified-Since: date, and the server checks if the resource changed. If not, it returns 304 with no body. The 304 response MUST include headers that would have been sent with a 200: Cache-Control, Content-Location, Date, ETag, Expires, Vary. This allows the client to update its cached response's metadata. ETag comparison is stronger than Last-Modified (which has 1-second granularity). Weak ETags (W/"tag") allow 304 for semantically equivalent representations.

Real-world examples

Common 304 Not Modified scenario 1
When a server returns 304 Not Modified, it signals specific behavior that clients and intermediaries must handle correctly. For example, in web applications, this status is commonly encountered during URL routing, content negotiation, or resource management operations.
CDN and proxy behavior with 304
CDNs and reverse proxies handle 304 Not Modified according to their configuration. The caching and forwarding behavior depends on whether the status is cacheable by default (per RFC 7231) and the presence of Cache-Control headers. Misconfigured intermediaries can cause redirect loops or cache stale redirects.
API design with 304 Not Modified
In RESTful API design, 304 Not Modified serves a specific semantic purpose. API gateways may intercept and modify these responses for versioning, rate limiting, or traffic management. Understanding when to use 304 versus similar status codes is critical for correct client behavior.

Framework behavior

Express.js (Node)
Express: res.redirect(304, 'https://new-url.com'). For 301/308 permanent: ensure the Location header is correct as browsers may cache it permanently.
Django / DRF (Python)
Django: return HttpResponseRedirect('/new-url/', status=304) or use the shortcut redirect() with permanent parameter for 301/308.
Spring Boot (Java)
Spring: return ResponseEntity.status(304).header("Location", "/new-url").build(). Spring's RedirectView can be configured with specific status codes.
FastAPI (Python)
FastAPI: return RedirectResponse(url='/new-url', status_code=304). For API redirects, ensure the client follows redirects with method preservation when using 307/308.

Debugging guide

  1. Check the Location header value — typos or relative URLs in Location can cause redirect loops or 404s
  2. Verify caching behavior: NOT cacheable by default — check Cache-Control headers
  3. Test with curl -v -L to follow redirects and see the full chain
  4. Check for redirect chains — each hop adds latency; aim for direct redirects
  5. Monitor for method preservation — 304 must keep the original method

Code snippets

Node.js
app.get('/old-path', (req, res) => {
  res.redirect(304, '/new-path');
});
Python
from fastapi.responses import RedirectResponse

@app.get('/old-path')
async def old_path():
    return RedirectResponse('/new-path', status_code=304)
Java (Spring)
@GetMapping("/old-path")
public ResponseEntity<Void> oldPath() {
    return ResponseEntity.status(304)
        .header("Location", "/new-path")
        .build();
}
Go
func oldPathHandler(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "/new-path", 304)
}

FAQ

When should I use 304 Not Modified vs other redirect codes?
304 Not Modified is temporary and has specific semantics. Choose based on permanence (will the redirect stay?) and method preservation (does POST need to stay POST?).
How do search engines handle 304 Not Modified?
Search engines follow the redirect but maintain the original URL in their index.
Is 304 Not Modified cacheable?
304 has special caching considerations depending on the implementation.
What are common pitfalls with 304 Not Modified?
Common issues include: redirect loops (A→B→A), missing Location header, relative vs absolute URLs in Location, browser compatibility issues, and excessive redirect chains that add latency.

Client expectation contract

Client can assume
  • A different URI is involved; Location may be required.
Client must NOT assume
  • Redirects will be followed automatically by all clients.
Retry behavior
Retries are generally unnecessary; treat as final unless domain rules require revalidation.
Monitoring classification
Redirect (policy-dependent)
Validate Location, caching headers, and chain behavior. Redirect loops/chains should alert.

Related status codes

303 See Other
The response to the request can be found under another URI using a GET method.
305 Use Proxy
DEPRECATED. Originally indicated that the requested resource must be accessed through a proxy. Deprecated in RFC 7231 due to security concerns and should not be used.

Explore more

Related guides
Related tools
Related utilities