How Content-Hashed Filenames (app.8f92a.js) and Cache-Control: immutable Make Repeat Visits Load in 0ms
The 304 Revalidation Tax: Why Your “Cached” Website is Still Slow
Web performance discussions are obsessed with initial page load metrics: Time to First Byte (TTFB), First Contentful Paint (FCP), and Largest Contentful Paint (LCP). Teams spend weeks optimizing bundle sizes and tuning CDN edge locations.
Yet for any successful SaaS application, e-commerce storefront, or content publication, over 70% of daily pageviews come from repeat visitors.
What happens when a repeat visitor clicks a link or hits the refresh button on your site?
If your server delivers assets with naive caching headers like Cache-Control: max-age=3600, the browser does not load the page instantaneously. Instead, it enters a round-trip negotiation with your server known as conditional revalidation:
THE 304 NOT MODIFIED CONDITIONAL TAX
- Repeat Visitor Clicks “Refresh” (F5): Browser Has /assets/app.js in local disk cache (Expires in 45 minutes)
- Browser Thinks: “Did the file change on the server? I must revalidate!”
- Browser GET /assets/app.js (If-None-Match: “etag-9182a”) → Nginx
- Nginx inspects disk inode → Matches ETag → Emits HTTP 304
- Browser → HTTP/2 304 Not Modified (Incurs 45ms Network RTT!)
- Repeat visit took 150ms just waiting for 20 unnecessary 304 round-trips!
Even though the payload body was not retransmitted, the browser still waited for a full network round-trip time (RTT) for every single stylesheet, JavaScript chunk, and SVG icon on the page. On a mobile connection with 80ms latency, 15 asset revalidations delay page rendering by hundreds of milliseconds.
The deterministic engineering solution is pairing Content-Hashed Filenames with Cache-Control: public, max-age=31536000, immutable.
At our engineering studio, our high-performance websites and fast static websites implement this dual caching architecture to deliver genuine 0ms repeat page loads.
The Two-Tier Caching Architecture: Mutable HTML vs. Immutable Assets
To achieve zero-millisecond reloads without risking stale code caching, you must divide your web assets into two strictly segregated categories:
THE DUAL-TIER CACHE SPLIT PATTERN
- TIER 1: THE ENTRYPOINT (index.html)
- Header: Cache-Control: no-cache
- Always revalidates with server (Takes ~10ms for tiny 5KB HTML)
- References the latest hashed bundles:
- TIER 2: THE CONTENT-HASHED ASSETS (/assets/*.[hash].js, .css, .woff2)
- Header: Cache-Control: public, max-age=31536000, immutable
- Stored in browser memory/disk cache for 1 FULL YEAR (31,536,000 seconds)
- NEVER touches the network again! Zero round-trips! Instant 0ms execution!
How the Contract Works:
- When a visitor navigates to your site, the browser requests
index.html. Because it hasCache-Control: no-cache, the browser checks with the server to ensure it has the latest version. - The HTML document arrives in 10ms, containing the current asset references:
style.7f19b.cssandmain.8a2c1.js. - When the browser parser reads
<script src="/assets/main.8a2c1.js">, it checks its local cache. - Because the asset was tagged as
immutable, the browser knows that filemain.8a2c1.jscan never mutate. - It reads the file directly from local NVMe or RAM in 0.00 milliseconds. No HTTP request is dispatched. No socket is opened.
What Happens During a Production Deployment?
What happens when you deploy new code?
In naive caching architectures, developers fear long cache headers because users get stuck with stale cached files. But with content hashing, stale cache issues are mathematically impossible.
CACHE INVALIDATION VIA CONTENT HASH MUTATION
- RELEASE N (Yesterday): index.html → points to → /assets/app.8f92a.js (Cached locally for 1 year)
- RELEASE N+1 (Today - Developer changes 1 line of CSS): index.html → points to → /assets/app.44b1c.js (Brand-New Filename!)
- Browser fetches fresh index.html (no-cache)
- Browser sees NEW URL: /assets/app.44b1c.js
- Result: Cache miss! Downloads new asset immediately!
- Old asset (app.8f92a.js) expires naturally in browser cache without collision.
Because the cryptographic hash is calculated from the compiled byte contents of the file, any change—whether a bugfix, a CSS color tweak, or a major framework upgrade—automatically produces a completely distinct URL.
The old file remains cached in the visitor’s browser for legacy sessions, while the new file is fetched cleanly on the very next visit.
Configuring Nginx for 0ms Immutable Caching
Let us configure Nginx on Debian 12 to enforce this two-tier caching contract with mathematical precision.
Edit your domain’s server block configuration file:
server {
listen 443 ssl http2;
server_name example.com;
root /home/admin/web/example.com/public_html;
# 1. TIER 1: HTML Documents (Never cache statically!)
location ~* \.html?$ {
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
expires -1;
}
# 2. TIER 2: Content-Hashed Static Assets (Vite, Astro, Webpack, Rollup)
# Target files matching .[hash].ext or inside /assets/ or /_astro/
location ~* ^/(assets|_astro|build)/.+\.(js|css|woff2|png|jpg|webp|svg)$ {
# Cache for 1 Year (365 Days) and mark as completely IMMUTABLE
add_header Cache-Control "public, max-age=31536000, immutable" always;
# Disable access logging for immutable assets to save disk I/O
access_log off;
log_not_found off;
# Enable high-speed zero-copy kernel file transmission
sendfile on;
tcp_nopush on;
tcp_nodelay on;
}
# 3. Fallback for unhashed static files (e.g., favicon.ico, robots.txt)
location ~* \.(ico|txt|xml)$ {
add_header Cache-Control "public, max-age=86400" always;
}
}
VERIFYING HEADERS FROM THE LINUX CLI
- $ curl -I https://example.com/
- HTTP/2 200 content-type: text/html; charset=UTF-8 cache-control: no-cache, no-store, must-revalidate
- $ curl -I https://example.com/assets/app.8f92a.js
- HTTP/2 200 content-type: application/javascript cache-control: public, max-age=31536000, immutable
Edge CDN Integration: Cloudflare & Reverse Proxies
When routing traffic through Cloudflare, the immutable directive delivers massive operational advantages.
By default, edge CDNs periodically revalidate assets against your origin server based on Edge Cache TTL rules. However, when Cloudflare encounters Cache-Control: public, max-age=31536000, immutable, its edge nodes recognize that the file will never alter.
EDGE CDN SHIELDING WITH IMMUTABLE HEADERS
- 1,000,000 Global Visitors Hit Edge Network
- Cloudflare Edge CDN (Lisbon, Frankfurt, London, New York)
- Holds asset in edge RAM/SSD cache with 1-Year TTL
- Origin Web Server: Receives ZERO asset traffic!
- Origin CPU: 1% | Bandwidth: Only serving dynamic HTML documents!
This configuration protects your backend origin server from high-traffic spikes. Even during massive traffic surges or viral campaigns, 99.8% of your asset bandwidth is absorbed entirely by browser caches and edge CDN nodes.
Audit Your Cache in DevTools: The “from disk cache (0 ms)” Proof
How do you confirm that immutable caching is functioning for your visitors? Open your browser’s Developer Tools (F12), navigate to the Network tab, and reload the page:
BROWSER NETWORK DEVTOOLS INSPECTION
- Name index.html
- Status Type Size Time: 200 html 4.8 kB 12 ms (Revalidated) app.8f92a.js 200 js (disk cache) 0 ms → IMMUTABLE! vendor.7c11b.js 200 js (memory cache) 0 ms → IMMUTABLE! style.99b2c.css 200 css (disk cache) 0 ms → IMMUTABLE! inter.woff2
- 200 font (disk cache) 0 ms → IMMUTABLE!
Notice the Size and Time columns:
- Instead of showing
304 Not Modifiedand45ms, the browser reports(disk cache)or(memory cache)and0 ms. - The assets did not traverse Wi-Fi, 5G, or fiber optics. They were retrieved from local memory in less than a single millisecond.
By combining content-hashed asset bundles with RFC 8246 Cache-Control: immutable, you deliver blistering, instant page navigations for your returning users while slashing origin server load to near zero. Following our core anti-over-engineering principles, you achieve sub-millisecond frontend performance using simple, standard HTTP semantics. Check out modern build presets on GitHub to ensure your build bundler outputs cryptographic content hashes automatically.
Alongside our operational work at Webxtek Studio, we apply these exact architectural standards across specialized sectors including b2b saas platforms and devops & cloud architecture specialists. Whether you are modernizing core workflows through high-performance websites and anti-over-engineering, connecting sector-specific requirements to disciplined execution is what turns technical theory into compounding commercial advantage.
[+] [ INDEX_DIRECTORY ] 15 topics ▼
- The 304 Revalidation Tax: Why Your “Cached” Website is Still Slow
- The Two-Tier Caching Architecture: Mutable HTML vs. Immutable Assets
- How the Contract Works:
- What Happens During a Production Deployment?
- Configuring Nginx for 0ms Immutable Caching
- Edge CDN Integration: Cloudflare & Reverse Proxies
- Audit Your Cache in DevTools: The “from disk cache (0 ms)” Proof
- Author
- Frequently Asked Questions
- What is content hashing in modern frontend build tools?
- What does the immutable directive in Cache-Control actually do?
- Why must index.html NEVER be served with Cache-Control: immutable?
- How does immutable caching reduce server CPU and bandwidth on Nginx?
- Related Nodes
- Path Sequence
Frequently Asked Questions
What is content hashing in modern frontend build tools?
Content hashing is the build-time technique of calculating a cryptographic checksum (such as SHA-256 or xxHash) of a file's compiled contents and appending that digest directly into the filename (e.g., `main.c83a1b.js`). If a single byte of source code changes, the filename changes; if the source code is untouched, the filename remains identical across deployments.
What does the immutable directive in Cache-Control actually do?
Introduced in RFC 8246, `Cache-Control: public, max-age=31536000, immutable` instructs the web browser that the file's contents will never change during its valid lifetime. Even when a user clicks the browser 'Refresh' button (F5), the browser completely bypasses the network, serving the asset directly from disk or memory cache in 0ms without sending conditional `If-None-Match` (304) requests.
Why must index.html NEVER be served with Cache-Control: immutable?
The entry HTML document (`index.html`) contains the script tags referencing the content-hashed asset filenames. If `index.html` is cached immutably, visitors will never receive updated links to new releases, permanently locking them into obsolete versions. The HTML must always be served with `Cache-Control: no-cache`.
How does immutable caching reduce server CPU and bandwidth on Nginx?
When browsers send 304 revalidation requests (`If-Modified-Since` or `If-None-Match`), Nginx must still parse TLS records, evaluate disk inodes or calculate ETags, and emit an HTTP header response. Immutable caching eliminates these revalidations entirely, reducing server connection overhead to zero for repeat visitors.
[ RELATED_NODES ]
> START_PROJECT
Need a website that earns trust, ranks in search, and gives your business a stronger digital presence? Start the conversation here.