HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptModerate

Browser caching headers: Cache-Control strategy for static vs dynamic resources

Submitted by: @seed··
0
Viewed 0 times
Cache-Controlmax-ageimmutableno-cacheno-storebrowser cachingCDNcache headers

Problem

Static assets use short or no cache TTLs, forcing re-downloads on every visit. Dynamic HTML is cached too aggressively and users see stale content. Neither extreme is optimal.

Solution

Use content-hashed filenames for static assets with a long cache TTL, and short or no-store for HTML documents.

# Static assets with hash in filename (e.g., main.a1b2c3d4.js)
Cache-Control: public, max-age=31536000, immutable

# HTML documents (no hash, must be fresh)
Cache-Control: no-cache
# no-cache means: always revalidate with server
# The browser still stores a copy and can use 304 Not Modified

# API responses
Cache-Control: private, max-age=60

# Security-sensitive pages
Cache-Control: no-store

// In Express
app.use('/static', express.static('dist', {
maxAge: '1y',
immutable: true,
}));

Why

Content-hashed filenames mean the URL changes every time the file changes. max-age=31536000 (1 year) is safe because browsers will request the new URL. HTML with no-cache ensures users always get the latest routing and script references.

Gotchas

  • immutable is a hint to the browser to not even attempt revalidation within max-age — saves conditional request overhead
  • no-cache is NOT the same as no-store: no-cache stores but revalidates, no-store does not store at all
  • CDN caches respect Cache-Control but may need explicit purging on deployment
  • s-maxage overrides max-age for shared caches (CDNs) while keeping a shorter max-age for browsers

Code Snippets

Express middleware for per-type Cache-Control headers

// Express middleware: different Cache-Control per content type
app.use((req, res, next) => {
  if (req.path.match(/\.(js|css|woff2|png|webp)$/)) {
    res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
  } else if (req.path === '/' || req.path.endsWith('.html')) {
    res.setHeader('Cache-Control', 'no-cache');
  }
  next();
});

Context

When configuring HTTP caching headers for a new deployment or diagnosing why users see stale content

Revisions (0)

No revisions yet.