← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

HTTP Caching (ETags, Cache-Control)

performance Intermediate

Also Known As

HTTP cache Cache-Control ETag Last-Modified

TL;DR

Standard HTTP headers that instruct browsers and intermediary caches on how long to cache responses and when to revalidate.

Explanation

HTTP caching is controlled primarily by Cache-Control (max-age, no-cache, no-store, public/private), ETags (opaque hash of response content enabling conditional requests), and Last-Modified. Correct caching headers can eliminate round-trips entirely for static assets and reduce server load for API responses. In PHP, set cache headers explicitly with header() — framework responses typically provide helper methods. For dynamic content, use Vary headers to cache different representations correctly and implement conditional GET responses that return 304 Not Modified without a body.

Common Misconception

Setting Cache-Control: no-cache means the response is never cached. no-cache means the browser must revalidate with the server before using the cached copy — the response is still stored locally. no-store is the directive that prevents caching entirely.

Why It Matters

HTTP caching headers let browsers and CDNs serve content without hitting your server — correct cache directives can eliminate 80%+ of requests for static and semi-static content.

Common Mistakes

  • No Cache-Control header — browsers guess, often defaulting to no caching.
  • Cache-Control: no-cache on truly static assets — forces revalidation on every request.
  • Not using ETags or Last-Modified for dynamic content that rarely changes.
  • Caching responses that contain user-specific data without Vary: Cookie or private directive.

Code Examples

✗ Vulnerable
// No cache headers — browser re-fetches on every navigation:
header('Content-Type: application/json');
echo json_encode($data);
// Should add: header('Cache-Control: public, max-age=300');
// Or for user data: header('Cache-Control: private, max-age=60');
✓ Fixed
// ETags — conditional GET, saves bandwidth
public function show(int $id): Response {
    $user = $this->users->find($id);
    $etag = md5($user->updatedAt->format('U'));

    if ($this->request->header('If-None-Match') === $etag) {
        return response('', 304); // Not Modified — no body sent
    }

    return response()->json($user)
        ->header('ETag', $etag)
        ->header('Cache-Control', 'private, must-revalidate');
}

// Static assets — immutable long cache
header('Cache-Control: public, max-age=31536000, immutable');

// API responses — short cache, must revalidate
header('Cache-Control: private, max-age=60, must-revalidate');

Added 15 Mar 2026
Edited 22 Mar 2026
Views 36
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 2 pings S 1 ping M 1 ping T 2 pings W 0 pings T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 2 pings S 1 ping S 0 pings M 1 ping T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Perplexity 10 Amazonbot 8 Ahrefs 6 Google 4 Unknown AI 2 SEMrush 2 Majestic 1
crawler 30 crawler_json 3
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Set Cache-Control: public, max-age=31536000, immutable on hashed static assets; Cache-Control: no-store on authenticated pages; ETag or Last-Modified on public but changeable content
📦 Applies To
any web api
🔗 Prerequisites
🔍 Detection Hints
Static assets without Cache-Control header; no-cache on all responses including static files; missing ETag on cacheable resources
Auto-detectable: ✓ Yes lighthouse curl webpagetest
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: File

✓ schema.org compliant