Favicon Caching Strategy Guide

Complete guide to favicon caching: browser cache behavior, optimal server headers, CDN configuration, and effective cache invalidation strategies.

Why Favicon Caching Matters

99%

Requests eliminated

0ms

Load time when cached

1 year

Recommended duration

20KB

Bandwidth saved/visit

Understanding Cache Levels

1. Browser Cache

Location: User's device

Duration: Based on headers

Control: Cache-Control headers

Impact: Fastest (0ms)

2. CDN Cache

Location: Edge servers

Duration: CDN configuration

Control: CDN settings + headers

Impact: Very fast (10-50ms)

3. Proxy Cache

Location: ISP/corporate

Duration: Varies

Control: public/private directives

Impact: Fast (50-100ms)

Optimal Cache Headers

Recommended Configuration

Perfect Cache Headers for Favicons:

Cache-Control: public, max-age=31536000, immutable
Expires: [Date 1 year from now]
ETag: "abc123def456"
Directive Value Purpose
public - Allow caching by browsers and CDNs
max-age 31536000 Cache for 1 year (in seconds)
immutable - Never revalidate (file won't change)
Expires [Date] HTTP/1.0 compatibility (backup)
ETag [Hash] Conditional requests (optional)
Why 1 year? Favicons rarely change. 1 year is maximum recommended by HTTP spec. Use versioned URLs (favicon.ico?v=2) when updating.

Server Configuration Examples

# Nginx favicon caching
server {
    # All favicon files
    location ~* \.(ico|png|svg|webmanifest|xml)$ {
        # 1 year cache
        expires 1y;
        
        # Cache-Control headers
        add_header Cache-Control "public, immutable" always;
        
        # Optional: ETag
        etag on;
        
        # Don't log these requests
        access_log off;
    }
    
    # Specific favicon.ico
    location = /favicon.ico {
        expires 1y;
        add_header Cache-Control "public, immutable" always;
        log_not_found off;
        access_log off;
    }
}

# Apache .htaccess or httpd.conf

# Enable expires module
<IfModule mod_expires.c>
    ExpiresActive On
    
    # Favicon files - 1 year
    ExpiresByType image/x-icon "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 year"
    ExpiresByType application/manifest+json "access plus 1 year"
</IfModule>

# Cache-Control headers
<IfModule mod_headers.c>
    <FilesMatch "\.(ico|png|svg|webmanifest)$">
        Header set Cache-Control "public, max-age=31536000, immutable"
    </FilesMatch>
</IfModule>

# Optional: Disable ETag to save bandwidth
FileETag None

<!-- IIS web.config -->
<configuration>
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" 
                   cacheControlMaxAge="365.00:00:00" />
    </staticContent>
    
    <outboundRules>
      <rule name="Add immutable">
        <match serverVariable="RESPONSE_Cache-Control" 
               pattern=".*" />
        <conditions>
          <add input="{REQUEST_FILENAME}" 
               pattern="\.(ico|png|svg)$" />
        </conditions>
        <action type="Rewrite" value="public, max-age=31536000, immutable" />
      </rule>
    </outboundRules>
  </system.webServer>
</configuration>

// Express.js favicon caching
const express = require('express');
const app = express();

// Static files with caching
app.use(express.static('public', {
  maxAge: '1y', // 1 year
  immutable: true,
  setHeaders: (res, path) => {
    if (path.match(/\.(ico|png|svg|webmanifest)$/)) {
      res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
    }
  }
}));

// Or specific route
app.get('/favicon.ico', (req, res) => {
  res.set('Cache-Control', 'public, max-age=31536000, immutable');
  res.sendFile(__dirname + '/public/favicon.ico');
});

CDN Caching Configuration

Cloudflare

Default: Respects origin headers

Edge TTL: 1 year recommended

Page Rule Configuration:
URL: *favicon* OR *.ico OR *.png
Setting: Edge Cache TTL = 1 year
Browser Cache TTL = Respect Existing

Purge cache: Purge Everything or specific URLs

AWS CloudFront

Behavior: Create path pattern

TTL: Min=31536000, Default=31536000, Max=31536000

Path Patterns:
/favicon.ico
/favicon-*.png
/*.svg
/site.webmanifest

Invalidation: Create invalidation for updated files

Browser-Specific Caching Behavior

Browser Cache Behavior Cache Location Clear Method
Chrome Aggressive, respects headers Disk + Memory Ctrl+Shift+Delete or Ctrl+F5
Firefox Very persistent (favicons.sqlite) Database + Disk Clear history or delete DB file
Safari Aggressive, long retention Disk cache Clear history or Cmd+Shift+R
Edge Similar to Chrome Disk + Memory Ctrl+Shift+Delete
Mobile Safari Extremely persistent for home screen Permanent until icon removed Delete & re-add home screen icon

Cache Invalidation Strategies

How to Update Cached Favicons

Strategy 1: Versioned URLs (Recommended)

<!-- Add version query parameter -->
<link rel="icon" href="/favicon.ico?v=2">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?v=2">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png?v=2">
<link rel="icon" type="image/png" sizes="512x512" href="/favicon-512x512.png?v=2">

<!-- Or change filename -->
<link rel="icon" href="/favicon-v2.ico">
<link rel="apple-touch-icon" href="/apple-touch-icon-v2.png">

? Pros:

  • Instant cache bypass
  • Works for all users immediately
  • No server-side changes needed
  • CDN-friendly

? Cons:

  • Need to update HTML
  • Query parameters may be stripped by some proxies
  • Old files remain on server

Strategy 2: Cache Purging

CDN Purge:
# Cloudflare CLI
cf-cli purge https://domain.com/favicon.ico

# AWS CloudFront
aws cloudfront create-invalidation --distribution-id X --paths "/favicon.ico"
Browser Cache:
  • Can't force users to clear
  • Hard refresh helps (Ctrl+F5)
  • Private browsing sees new version
  • Wait for cache expiry
Best Practice: Use versioned URLs for critical updates. Let cache expire naturally for minor tweaks.

Testing Cache Configuration

Verify Caching is Working

1. Check Headers with curl:

# Check cache headers
curl -I https://yourdomain.com/favicon.ico

# Expected output should include:
# Cache-Control: public, max-age=31536000, immutable
# Expires: [Date 1 year from now]

# Check if gzipped (for SVG)
curl -H "Accept-Encoding: gzip" -I https://yourdomain.com/favicon.svg
# Look for: Content-Encoding: gzip

2. Browser DevTools:

  1. Open DevTools (F12) ? Network tab
  2. Reload page (F5)
  3. Find favicon.ico in list
  4. Check Size column - should show "disk cache" or "memory cache" on second load
  5. Check Headers tab for Cache-Control

3. Online Tools:

Common Caching Issues & Solutions

Solutions (in order):
  1. Add version parameter: favicon.ico?v=2
  2. Purge CDN cache if using CDN
  3. Hard refresh browser: Ctrl+Shift+R or Ctrl+F5
  4. Clear browser cache completely
  5. Test in Private/Incognito window
  6. Wait for cache to expire naturally (up to 1 year!)

Check:
  • Server module enabled (mod_expires for Apache)
  • Configuration syntax correct
  • Server restarted after config change
  • Not being overridden by application
  • Using correct file path/location blocks
  • Test with curl to verify headers

Cause: Each browser implements caching differently.
Solution:
  • Set consistent headers for all browsers
  • Use both Cache-Control and Expires
  • Add immutable directive
  • Test in all major browsers
  • Version URLs for critical updates

Caching Best Practices Summary

? Do This

  • Set 1-year cache for favicons
  • Use immutable directive
  • Include both Cache-Control and Expires
  • Version URLs when updating
  • Enable CDN caching
  • Test with multiple browsers
  • Monitor cache hit rates
  • Document cache strategy

? Avoid This

  • Short cache durations (< 1 month)
  • no-cache or no-store directives
  • Relying on ETag only (uses bandwidth)
  • Forgetting Expires header
  • Not versioning for updates
  • Disabling cache in production
  • Ignoring CDN cache settings
  • Not testing cache behavior

Generate Cache-Optimized Favicons

Our generator includes optimal caching instructions

Generate Favicons

Related Articles

An unhandled error has occurred. Reload 🗙