Skip to content

Cache Control: Advanced HTTP Caching Directives for Modern APIs

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Cache Control: Advanced HTTP Caching Directives for Modern APIs. We cover key concepts, practical examples, and best practices to help you master this topic.

Beyond basic max-age and public, modern HTTP caching offers advanced directives that enable sophisticated cache behaviors: serving stale content during revalidation (stale-while-revalidate), caching on errors (stale-if-error), and declaring immutability for versioned assets.

flowchart LR
    subgraph Freshness
        A[max-age=60]
        B[s-maxage=300]
    end
    subgraph Stale While Revalidate
        C[SWR=3600]
        D[SIE=86400]
    end
    subgraph Immutable
        E[immutable]
    end
    A -->|Fresh| F[Serve Cache]
    A -->|Stale| C
    C -->|Background Revalidation| G[Return Stale Immediately]
    C -->|Revalidated| F
    A -->|Error| D
    D -->|Serve Stale on 5xx| H[Return Stale Cached]
    E -->|Versioned Asset| I[Cache Forever]

What You'll Learn

  • The stale-while-revalidate and stale-if-error directives
  • The immutable extension for fingerprinted assets
  • CDN-specific headers: Cloudflare CDN-Cache-Control, Akamai Edge-Control
  • Surrogate-Control for reverse proxy differentiation

Why It Matters

Stale-while-revalidate dramatically improves perceived performance by serving instant responses while fetching fresh data in the background. This pattern is essential for APIs where users tolerate slightly stale data for the benefit of speed.

Real-World Use

A news API sets Cache-Control: public, max-age=10, stale-while-revalidate=86400. Readers see articles that are up to 10 seconds old instantly. In the background, the browser fetches fresh data. If the API is down, content stays available for up to 24 hours.

Advanced Directives

Stale-While-Revalidate

app.get('/api/news', async (req, res) => {
  res.set('Cache-Control', 'public, max-age=30, stale-while-revalidate=3600');
  const news = await db.getLatestNews();
  res.json(news);
});

Expected output:

Within 30s: cached fresh. Between 31s and 3630s: cache serves stale immediately, fetches update in background.

Stale-If-Error

app.get('/api/weather/:city', async (req, res) => {
  res.set('Cache-Control', 'public, max-age=60, stale-if-error=86400');
  try {
    const weather = await weatherService.fetch(req.params.city);
    res.json(weather);
  } catch (err) {
    // If cache exists and we get here, CDN/browser will serve stale cached version
    throw err;
  }
});

Expected output:

If the weather service is down, CDN serves the cached response (up to 24h old) instead of showing an error.

Immutable for Versioned Assets

app.get('/static/js/bundle.a1b2c3.js', (req, res) => {
  res.set('Cache-Control', 'public, max-age=31536000, immutable');
  res.sendFile(bundlePath);
});

Expected output:

Browser caches this file for 1 year. The immutable directive tells browsers not to revalidate on page reload — the file never changes because the filename includes a content hash.

Surrogate-Control for CDN Differentiation

app.get('/api/popular', (req, res) => {
  res.set('Cache-Control', 'private, max-age=0');
  res.set('Surrogate-Control', 'public, max-age=300');
  res.json(getPopular());
});

Expected output:

Browser does not cache (private). CDN caches for 300 seconds (Surrogate-Control), reducing origin load for popular content.

Common Mistakes

  • Using stale-while-revalidate without max-age — the stale period has no effect if the resource never becomes stale.
  • Setting max-age too high for frequently changing content, forcing background revalidation every time.
  • Forgetting that stale-if-error only works if a valid cached response exists before the error occurs.
  • Using immutable on non-fingerprinted assets — if the URL doesn't change with content, immutable prevents users from seeing updates.
  • Mixing Cache-Control with Pragma or Expires inconsistently, causing confusing cache behavior in older browsers.

Practice Questions

  1. What happens when stale-while-revalidate expires?
  2. How does stale-if-error protect against backend failures?
  3. Why should you only use immutable on content-hashed or versioned URLs?
  4. What is the difference between Surrogate-Control and Cache-Control?
  5. How does a CDN behave when Cache-Control says private but Surrogate-Control says public?

Challenge

Design a caching policy for a live sports scores API. Updates arrive every 5 seconds. Users should see scores instantly (max-age 1s), tolerate 30-second stale scores while revalidating, and if the origin fails, serve scores up to 1 hour old.

FAQ

What is stale-while-revalidate?

It allows serving stale cached content immediately while the browser or CDN fetches a fresh version in the background. The response indicates how long this stale-serving is permitted.

Is stale-while-revalidate supported by all browsers?

Chrome and Firefox support it since 2017. Safari added support in 2021. For CDNs (Cloudflare, Fastly), it works at the edge regardless of browser support.

What does the immutable directive do?

immutable tells the browser not to revalidate the resource on page reload. It's safe only when the URL changes with content (e.g., hash in filename).

How do I set different cache policies for CDN vs browser?

Use Cache-Control for browser policy and Surrogate-Control (or CDN-Cache-Control for Cloudflare) for the CDN. The CDN respects Surrogate-Control and forwards Cache-Control to the browser.

What is the maximum useful stale-while-revalidate value?

It depends on how stale your users will tolerate. For content that changes infrequently, 86400 (24h) is common. For real-time data, keep it under 300 (5 min).

Mini Project

Create an Express server with three endpoints demonstrating stale-while-revalidate, stale-if-error, and immutable. Use curl to verify behavior. For the stale-if-error demo, simulate a backend failure after initial cache fill and confirm the stale response is served.

What's Next

Continue with CDN Caching to learn how content delivery networks cache and serve content at the edge.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro