How to Choose Between Content Hash and Version Hash for Static Assets
Mismatched fingerprinting strategies cause stale asset delivery, 404 Not Found errors, and CDN cache poisoning. This guide provides a symptom-to-resolution workflow for selecting between content-based hashing (file-level) and version-based hashing (release-level). Align your strategy with build determinism, CDN purge economics, and rollback requirements. Reference the Static Asset Fingerprinting Fundamentals for baseline HTTP header mechanics and URL routing patterns.
Symptom Identification & Cache Failure Modes
Stale JavaScript/CSS or broken module paths immediately following deployment indicate a cache invalidation misalignment. The root cause typically stems from CDN cache keys ignoring query-string or path-based fingerprint changes due to misconfigured Vary or Cache-Control directives.
Diagnostic Workflow:
- Audit origin responses against the build manifest.
- Verify hash generation aligns with collision tolerance thresholds detailed in MD5 vs SHA-256 for Assets.
- Run the following diagnostic command against the CDN edge:
curl -sI -H 'Pragma: no-cache' https://cdn.yourdomain.com/assets/main.[hash].js | grep -E 'etag|cache-control|age'
- Validate in Browser DevTools: Open the Network tab, disable cache, and reload. Filter by
JSorCSS. Check theSizecolumn for(disk cache),(memory cache), orfrom service worker. Cross-reference theResponse Headerswith your build output.
Expected Output Analysis:
Cache-Control: public, max-age=31536000, immutablewithage> 0 indicates a successful cache hit.304 Not Modifiedon updated assets confirms the CDN is serving stale fingerprints.404 Not Foundon newly deployed bundles confirms the HTML references a hash the CDN has not yet fetched or the origin routing is misconfigured.
Content Hashing: Mechanics & Granular Invalidation
Content hashing derives the URL fingerprint directly from raw file bytes (e.g., [contenthash:8].js). Only modified files generate new URLs. This strategy is mandatory for micro-frontend architectures, high-frequency deployments, and CDNs with strict per-object purge limits.
Architectural Requirements:
- Strictly deterministic build pipelines. Eliminate timestamps, random seeds, and non-reproducible toolchain outputs.
- Pair with
Cache-Control: public, max-age=31536000, immutableto enforce perpetual edge caching.
Webpack Configuration:
module.exports = {
output: {
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].chunk.js',
assetModuleFilename: 'assets/[hash][ext][query]'
},
optimization: {
moduleIds: 'deterministic',
runtimeChunk: 'single'
}
};
This configuration locks module IDs and isolates runtime chunks, preventing unnecessary cache invalidation when unrelated files change.
Version Hashing: Mechanics & Release-Level Control
Version hashing derives the fingerprint from a release tag, CI run ID, or package.json version (e.g., v2.4.1/app.js). All assets share a single cache-busting prefix. This approach suits regulated environments requiring audit trails, infrequent major releases, or legacy CDN setups with limited purge APIs.
Trade-offs & Advantages:
- Minor CSS changes trigger full asset invalidation, increasing origin load and CDN purge costs.
- Instant rollback capability: Route traffic to the previous version directory without triggering an origin re-fetch.
Nginx Routing Configuration:
location ~ ^/assets/v([0-9.]+)/(.*)$ {
alias /var/www/releases/v$1/static/$2;
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
This maps semantic version prefixes to release directories, enabling instant traffic shifting by updating the deployment manifest.
Decision Matrix: Content vs Version Hash Selection
| Criteria | Content Hash Strategy | Version Hash Strategy |
|---|---|---|
| Deployment Frequency | Daily/Continuous | Weekly/Monthly |
| Build Determinism | Strictly enforced (required) | Non-critical |
| CDN Purge Economics | High cost/limited API | Low cost/unlimited API |
| Compliance & Auditing | Per-file tracking | Single-version grouping |
| Rollback Complexity | Requires HTML manifest revert | Instant directory routing |
| SRI Enforcement | Requires attribute regeneration per build | Stable across minor updates |
Hybrid Architecture: Deploy version hashes exclusively for index.html and critical CSS entry points. Apply content hashes to vendor bundles, application chunks, and media assets. This balances cache efficiency with rollback safety.
Implementation & CDN Cache Key Alignment
Edge cache configuration must strictly align with the selected fingerprinting strategy. Misalignment causes origin bypass failures and cache fragmentation.
CloudFront Cache Policy:
{
"CachePolicyConfig": {
"Name": "Immutable-Asset-Policy",
"DefaultTTL": 31536000,
"MaxTTL": 31536000,
"MinTTL": 0,
"ParametersInCacheKeyAndForwardedToOrigin": {
"CookiesConfig": { "CookieBehavior": "none" },
"HeadersConfig": { "HeaderBehavior": "none" },
"QueryStringsConfig": { "QueryStringBehavior": "none" }
}
}
}
Strip cookies, query strings, and irrelevant headers from cache keys. Identical fingerprinted URLs must resolve to a single cached object across all edge PoPs.
Header Strategy: Always serve fingerprinted assets with the immutable directive. Reserve ETag validation exclusively for non-fingerprinted fallbacks or HTML entry points.
Validation Protocol: Execute synthetic cache-hit tests across multiple geographic edge locations. Verify zero-origin fetches for unchanged hashes using browser DevTools Network tab (filter by from disk cache or from memory cache). Monitor origin access logs for 200 responses on static paths during steady-state traffic.
Common Pitfalls & Incident Resolution
Pitfall 1: Non-deterministic builds altering content hashes on every CI run
- Root Cause: Build tools embedding timestamps, random UUIDs, or absolute file paths into compiled output.
- Resolution: Enable
optimization.moduleIds: 'deterministic', strip source maps from production builds, and enforce locked dependency versions inpackage-lock.json.
Pitfall 2: Version hash triggering full CDN purge on minor CSS updates
- Root Cause: All assets share a single version prefix, invalidating unchanged vendor bundles and images.
- Resolution: Split the fingerprinting strategy. Apply version hashes only to
index.htmland entry points. Retain content hashes for static chunks and media.
Pitfall 3: Mixed hash strategies causing 404s during phased rollouts
- Root Cause: CDN caches old versioned paths while the origin serves new content-hashed URLs, breaking cross-references in HTML.
- Resolution: Deploy HTML templates last. Ensure
manifest.jsonmaps correctly to new hashes. ApplyCache-Control: no-cacheto HTML to force strict revalidation on every request.
Frequently Asked Questions
Can I use both content hashes and version hashes in the same deployment? Yes. Use version hashes for HTML entry points and critical CSS to enable instant rollbacks. Apply content hashes to JS bundles, fonts, and images for granular cache efficiency.
Does content hashing guarantee zero cache invalidation costs? No. If the build pipeline is non-deterministic, identical source code may produce different hashes, forcing unnecessary CDN purges. Deterministic builds are mandatory for cost efficiency.
How does Subresource Integrity (SRI) interact with version hashes? SRI requires exact byte-level matching. Version hashes change the URL but not the file content, so SRI remains valid across minor updates. Content hashes change both URL and content, requiring SRI attribute regeneration on each build.