Cache-Control: Cheat Sheet

5 min read

The Cache-Control header sets rules for how web pages are stored in browser and CDN caches. It tells them how to save pages and when to check if the pages need to be updated from the original server.

   Client <------ CDN <------ Server
     ↓             ↓            ↓
[Web Browser] [Shared Cache] [Origin Server]

Directives:

   Client <------ CDN <------ Server
     ✗             ✗
   Client <------ CDN <------ Server
     ↓             ↓
  Revalidate   Revalidate
   Client <------ CDN <------ Server
     ✓             ✗
   Client <------ CDN <------ Server
     ✓             ✓
   Client <------ CDN <------ Server
   max-age      max-age
   Client <------ CDN <------ Server
               s-maxage
   Client <------ CDN <------ Server
     ↓             ↓
  Revalidate   Revalidate
   Client <------ CDN <------ Server

               Revalidate
   Client <------ CDN <------ Server
     ✗             ✗
  Transform    Transform
   Client <------ CDN <------ Server
     ↓             ↓
 Serve Stale  Serve Stale
              Revalidate
   Client <------ CDN <------ Server
     ↓             ↓
 Serve Stale  Serve Stale
              Error Occurs

Note: Directives can be combined in a single Cache-Control header and they are case-insensitive.

Examples:

  1. Public Cache with 1 day max age

    • The response can be stored by any cache (browser or CDN) and is considered fresh for 1 day.

    Cache-Control: public, max-age=86400

  2. Private Cache with 1-hour max age

    • The response is intended for a single user and can be stored by the browser, but not shared caches like CDNs. It’s considered fresh for 1 hour.

    Cache-Control: private, max-age=3600

  3. No Cache

    • The response can be stored by the browser or CDN, but they must revalidate with the server before serving it.

    Cache-Control: no-cache

  4. No Store

    • The response must not be stored by any cache (browser, CDN, or server).

    Cache-Control: no-store

  5. Fresh for 1 hour, revalidate after that

    • The response is considered fresh for 1 hour, after which the cache must revalidate with the server before serving it.

    Cache-Control: max-age=3600, must-revalidate

  6. Public Cache, no transformation

    • The response can be stored by any cache (browser or CDN), but it must not be transformed by any intermediary.

    Cache-Control: public, no-transform

  7. Shared Cache with 2 hours max-age, private cache with 1-hour max age

    • The response can be stored by a shared cache (CDN) and is considered fresh for 2 hours. For private caches (browser), it’s considered fresh for 1 hour.

    Cache-Control: s-maxage=7200, max-age=3600

  8. Stale while revalidating for 1 hour

    • The browser or CDN can serve a stale response while it revalidates with the origin in the background for up to 1 hour.

    Cache-Control: stale-while-revalidate=3600

  9. Stale while revalidating for 1 hour, serve stale on error for 2 hours

    • The browser or CDN can serve a stale response while it revalidates with the origin in the background for up to 1 hour. If an error occurs during revalidation, the stale response can still be served for an additional 2 hours.

    Cache-Control: stale-while-revalidate=3600, stale-if-error=7200

Express Example:

The code snippet below sets caching rules for the response. It allows any cache to store the response (public). The response is considered current for 24 hours when cached by a browser (max-age=86400), and for 2 hours when stored by shared caches, such as CDNs (s-maxage=7200).

Additionally, if the response is outdated, both the browser and CDN can still temporarily deliver the old response while they update their cache with a new one, for up to 1 hour (stale-while-revalidate=3600).

import express from 'express';
const app = express();

app.get('/', (req, res) => {
  res.set(
    'Cache-Control',
    'public, max-age=86400, s-maxage=7200, stale-while-revalidate=3600'
  );

  res.send('Hello World');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

more posts

back