Skip to content

Browser Serving Stale Cache Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about Browser Serving Stale Cache Fix. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Browser Caching improves performance by storing resources locally. When content changes, users may see outdated pages if the cache headers are too aggressive or if cache-busting techniques are not used.

The Wrong Way

from flask import Flask, send_file

app = Flask(__name__)

@app.route("/script.js")
def serve_script():
    # No cache headers - browser guesses caching behavior
    return send_file("script.js")

Output:

# Browser caches script.js indefinitely
# Users see old JavaScript even after deployment

The Right Way

Set explicit cache headers and use cache busting:

from flask import Flask, send_file, make_response
import hashlib, os

app = Flask(__name__)

@app.route("/script-<version>.js")
def serve_script(version):
    response = make_response(send_file("script.js"))
    response.headers["Cache-Control"] = "public, max-age=31536000, immutable"
    return response

# Generate versioned URLs
def get_versioned_url(filename):
    with open(filename, "rb") as f:
        content_hash = hashlib.md5(f.read()).hexdigest()[:8]
    name, ext = os.path.splitext(filename)
    return f"/{name}-{content_hash}{ext}"

Step-by-Step Fix

1. Force hard refresh

# Chrome/Firefox/Edge
# Press Ctrl+F5 or Ctrl+Shift+R
# Or open DevTools -> right-click refresh -> Empty Cache and Hard Reload

2. Add cache-busting query parameters

<!-- Version as query parameter -->
<link rel="stylesheet" href="/style.css?v=2">

<!-- Build timestamp -->
<script src="/app.js?t=20260624"></script>

3. Use content hashing in filenames

// Webpack config for hashed filenames
module.exports = {
    output: {
        filename: "[name].[contenthash:8].js",
        chunkFilename: "[name].[contenthash:8].chunk.js"
    }
};

4. Set proper Cache-Control headers

# Static assets with immutable caching
location /static/ {
    root /var/www;
    expires 1y;
    add_header Cache-Control "public, immutable";
}

# HTML should never be cached
location / {
    add_header Cache-Control "no-cache, no-store, must-revalidate";
}

5. Clear service worker caches

// service-worker.js
self.addEventListener("activate", event => {
    event.waitUntil(
        caches.keys().then(cacheNames => {
            return Promise.all(
                cacheNames.map(name => caches.delete(name))
            );
        })
    );
});

6. Use ETag and Last-Modified headers

@app.route("/api/data")
def get_data():
    data = fetch_data()
    etag = hashlib.md5(str(data).encode()).hexdigest()

    response = jsonify(data)
    response.headers["ETag"] = etag

    # If client sends matching If-None-Match, return 304
    if request.headers.get("If-None-Match") == etag:
        return "", 304

    return response

Prevention Tips

  • Use content hashes in filenames for static assets.
  • Set Cache-Control: no-cache for HTML files.
  • Use Cache-Control: public, max-age=31536000, immutable for versioned assets.
  • Implement ETag headers for API responses.
  • Add a service worker update flow that clears old caches.

Common Mistakes with cache stale

  1. Using head and tail instead of pattern matching, causing runtime errors on empty lists
  2. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  3. Using return to exit a function early instead of wrapping a pure value in the monad

These mistakes appear frequently in real-world BROWSER code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### How do I force all users to see the latest version?

Update the version identifier in asset URLs (hash or query param). Users with old versions will request the new URL, which is not in their cache. The old cache entries will eventually expire.

What is the difference between no-cache and no-store?

no-cache forces the browser to check with the server before using a cached response (revalidation). no-store prevents the browser from storing any copy of the response at all.

Does a 304 response solve stale content?

Yes. A 304 Not Modified response tells the browser its cached version is still valid. But if content changed, the server returns 200 with new content, and the browser updates its cache.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro