Effective cache management is crucial for web application performance and ensuring users receive the latest updates. This guide covers cache busting strategies and performance optimization techniques.

Why Cache Management Matters

The Cache Dilemma

  • Performance vs. Freshness: Caching improves load times but can serve stale content
  • User Experience: Cached content loads faster but may not reflect recent changes
  • CDN Efficiency: Content delivery networks rely on aggressive caching for global performance
  • Development Challenges: Developers need to ensure updates reach users promptly

Common Cache Problems

  1. Stale Content: Users see outdated versions of your site
  2. Mixed Versions: Some files update while others remain cached
  3. Development Confusion: Changes don’t appear immediately during testing
  4. Deployment Issues: Production updates don’t propagate to users

Cache Busting Strategies

1. Version-Based Cache Busting

Add version parameters to asset URLs:

<!-- CSS with version parameter --> <link rel="stylesheet" href="/assets/main.css?v=1.2.3" /> <!-- JavaScript with version parameter --> <script src="/assets/app.js?v=1.2.3"></script> <!-- Images with cache busting --> <img src="/images/logo.png?v=1.2.3" alt="Logo" />

Pros:

  • Simple to implement
  • Works with any asset type
  • Easy to understand and debug

Cons:

  • Manual version management
  • All assets invalidated together
  • Query parameters may be ignored by some proxies

2. File Hash-Based Cache Busting

Use content hashes in filenames:

<!-- CSS with content hash --> <link rel="stylesheet" href="/assets/main-a1b2c3d4.css" /> <!-- JavaScript with content hash --> <script src="/assets/app-e5f6g7h8.js"></script>

Pros:

  • Automatic invalidation when content changes
  • Granular cache control per file
  • More reliable than query parameters

Cons:

  • Requires build process integration
  • More complex deployment
  • Need to update references

3. Directory-Based Versioning

Use version numbers in directory paths:

<!-- Versioned directory structure --> <link rel="stylesheet" href="/v1.2.3/assets/main.css" /> <script src="/v1.2.3/assets/app.js"></script>

Pros:

  • Clean separation of versions
  • Easy rollback capability
  • Clear version identification

Cons:

  • Increased storage requirements
  • Complex deployment process
  • Manual path management

Jekyll-Specific Cache Busting

Site Variables for Cache Busting

# _config.yml version: "1.2.3" cache_bust: 20240130-143022
<!-- In templates --> <link rel="stylesheet" href="/assets/main.css?v=1.0.0" /> <script src="/assets/app.js?v=true"></script>

Build-Time Cache Busting

# _config.yml plugins: - jekyll-cache-bust cache_bust: enabled: true strategy: "content_hash"

Liquid Template Cache Busting

<link rel="stylesheet" href="/assets/main.css?v=1760036520" />

HTTP Headers for Cache Control

Cache-Control Headers

# .htaccess for Apache <IfModule mod_expires.c> ExpiresActive on # CSS and JavaScript (1 year with versioning) ExpiresByType text/css "access plus 1 year" ExpiresByType application/javascript "access plus 1 year" # Images (1 month) ExpiresByType image/png "access plus 1 month" ExpiresByType image/jpg "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/svg+xml "access plus 1 month" # HTML (1 hour for dynamic content) ExpiresByType text/html "access plus 1 hour" </IfModule> # Cache control headers <IfModule mod_headers.c> # Versioned assets - cache aggressively <FilesMatch "\.(css|js|png|jpg|jpeg|gif|svg)$"> Header set Cache-Control "public, max-age=31536000, immutable" </FilesMatch> # HTML - short cache with revalidation <FilesMatch "\.html$"> Header set Cache-Control "public, max-age=3600, must-revalidate" </FilesMatch> </IfModule>

Nginx Configuration

# nginx.conf location ~* \.(css|js|png|jpg|jpeg|gif|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; add_header Vary Accept-Encoding; } location ~* \.html$ { expires 1h; add_header Cache-Control "public, must-revalidate"; }

Meta Tags for HTML Caching

<!-- Prevent caching of HTML pages --> <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="0" /> <!-- Or allow short-term caching --> <meta http-equiv="Cache-Control" content="public, max-age=3600" />

CDN and Performance Optimization

CDN Cache Busting

<!-- Version in CDN URLs --> <script src="https://cdn.example.com/v1.2.3/app.js"></script> <!-- Hash-based CDN URLs --> <link rel="stylesheet" href="https://cdn.example.com/main-a1b2c3d4.css" />

Preloading Critical Assets

<!-- Preload critical CSS --> <link rel="preload" href="/assets/critical.css?v=1.2.3" as="style" /> <!-- Preload important JavaScript --> <link rel="preload" href="/assets/app.js?v=1.2.3" as="script" /> <!-- Preload hero images --> <link rel="preload" href="/images/hero.jpg?v=1.2.3" as="image" />

Resource Hints

<!-- DNS prefetch for external resources --> <link rel="dns-prefetch" href="//cdn.example.com" /> <!-- Preconnect to external domains --> <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin /> <!-- Prefetch next page resources --> <link rel="prefetch" href="/next-page.html" />

Development vs. Production

Development Environment

# _config_dev.yml cache_bust: false version: "dev" # Disable caching in development plugins: - jekyll-cache-bust cache_bust: enabled: false

Production Environment

# _config_prod.yml cache_bust: true version: "1.2.3" # Enable aggressive caching in production plugins: - jekyll-cache-bust cache_bust: enabled: true strategy: 'content_hash' extensions: ['css', 'js', 'png', 'jpg']

Monitoring and Testing

Cache Validation Tools

  • Browser DevTools: Check cache status in Network tab
  • GTmetrix: Analyze caching effectiveness
  • WebPageTest: Detailed cache analysis
  • Lighthouse: Performance auditing with cache recommendations

Testing Cache Behavior

# Test cache headers curl -I https://yoursite.com/assets/main.css # Test with different user agents curl -H "User-Agent: Mozilla/5.0..." -I https://yoursite.com/ # Check cache validation curl -H "If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT" -I https://yoursite.com/

Cache Debugging

// Check if resource was served from cache window.addEventListener("load", function () { const entries = performance.getEntriesByType("resource"); entries.forEach((entry) => { if (entry.transferSize === 0) { console.log("From cache:", entry.name); } else { console.log("From network:", entry.name); } }); });

Best Practices

Asset Organization

  1. Separate Static from Dynamic: Cache static assets aggressively, dynamic content conservatively
  2. Version Critical Assets: Ensure important updates reach users quickly
  3. Use Immutable Caching: Set immutable flag for versioned assets
  4. Optimize Cache Hierarchies: Consider browser, CDN, and proxy caches

Deployment Strategies

  1. Atomic Deployments: Update all references simultaneously
  2. Graceful Rollouts: Allow time for cache propagation
  3. Rollback Preparation: Keep previous versions accessible
  4. Cache Warming: Pre-populate CDN caches after deployment

Performance Guidelines

  1. Minimize Cache Misses: Use predictable versioning schemes
  2. Optimize Cache Hit Ratio: Balance freshness with performance
  3. Reduce Cache Churn: Avoid unnecessary version bumps
  4. Monitor Cache Effectiveness: Track hit rates and performance impact