304 Not Modified

Redirect - Use cached version, resource unchanged

HTTP 304 Not Modified

What It Means

The HTTP 304 Not Modified status code indicates that the resource hasn't changed since the version in the browser's cache. The server tells the client to use its cached copy, saving bandwidth.

How It Works

  1. 1. Browser requests resource, server returns 200 + ETag/Last-Modified
  2. 2. Browser caches resource with those headers
  3. 3. On next request, browser sends If-None-Match or If-Modified-Since
  4. 4. If unchanged, server returns 304 (no body)
  5. 5. Browser uses cached version

Conditional Request Headers

Request Header Response Header
If-None-Match ETag
If-Modified-Since Last-Modified

Example Flow

Initial request:

GET /api/data HTTP/1.1
Host: example.com

HTTP/1.1 200 OK
ETag: "abc123"
Last-Modified: Mon, 15 Jan 2025 10:00:00 GMT
Content-Type: application/json

{"data": "value"}

Subsequent request (unchanged):

GET /api/data HTTP/1.1
Host: example.com
If-None-Match: "abc123"

HTTP/1.1 304 Not Modified
ETag: "abc123"

(no body)

Implementation

Express.js with ETag

const express = require('express');
const app = express();

// Express automatically handles ETags for static files
app.use(express.static('public'));

// For dynamic content
app.get('/api/data', (req, res) => {
  const data = getData();
  const etag = generateETag(data);

  if (req.headers['if-none-match'] === etag) {
    return res.status(304).end();
  }

  res.setHeader('ETag', etag);
  res.json(data);
});

Benefits

  • Bandwidth savings: No body sent on 304
  • Faster responses: Less data to transfer
  • Server load reduction: Can skip expensive operations
  • Still validates: Unlike pure cache, checks for updates

304 Response Rules

  • Must not contain a message body
  • Should include same headers as 200 would (ETag, Cache-Control, etc.)
  • Should include Date header

Monitor your cache performance

Track response times and cache hit rates with UptimeSignal.

Start monitoring free →

Related Status Codes