Browser Caching Issues
Understanding and fixing favicon and static asset caching problems
Why Does My Favicon Not Update? Understanding Browser Caching and How to Fix It
If you've deployed your React website and changed the favicon, but the old icon still shows up even after rebuilding and clearing your browser cache you're not alone. This is a very common issue caused by browser caching behavior and CDN/proxy caching layers (like Cloudflare). Here's what's going on and how to fix it.
What is a Favicon?
A favicon is the small icon displayed in browser tabs, bookmarks, and other UI elements. It is typically linked in your HTML with:
<link rel="icon" type="image/png" href="/favicon.png" />Why Does the Old Favicon Persist?
1. Browser Cache
Browsers aggressively cache favicons to avoid fetching them repeatedly on every page load. Even private/incognito mode may use some caching, especially if the resource has strong caching headers.
2. CDN or Proxy Cache
If you use a CDN or reverse proxy (e.g., Cloudflare Tunnel, Cloudflare CDN), the icon might be cached on those servers, serving stale content to clients.
3. No Cache-Busting Strategy
If the favicon URL never changes (always /favicon.png), browsers and proxies see it as the same resource and serve the cached version.
How to Fix It
1. Use Cache Busting Query Parameters
Change the favicon link to include a version query parameter, which forces browsers and proxies to treat it as a new resource:
<link rel="icon" type="image/png" href="/favicon.png?v=2" />When you update the favicon, increment the v number.
2. Set Proper Cache-Control Headers in Nginx
You want to cache static assets for performance, but sometimes it's better to set a reasonable max-age for favicons or disable caching temporarily during development.
Example in your nginx.conf:
location = /favicon.png {
expires 1d;
add_header Cache-Control "public, max-age=86400";
}Or to disable caching during development:
location = /favicon.png {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
}3. Make Sure the Correct Favicon Is Served
- Confirm your build process copies the favicon to the right folder (
dist/or/usr/share/nginx/html). - Check the file contents in your container or server to verify.
- If you serve multiple favicon sizes/types, verify all are up to date.
4. Clear CDN Cache or Purge Proxy Cache
If you use Cloudflare or other CDNs:
- Purge the cache for
/favicon.pngand/favicon.ico. - Temporarily disable caching for these files during debugging.
Summary
| Problem | Solution |
|---|---|
| Browser caching old favicon | Add version query parameter (?v=2) |
| CDN/proxy caching | Purge CDN cache, or disable caching for favicon |
| Nginx serving stale favicon | Configure proper cache headers |
| Build process missing favicon | Ensure favicon copied during build |
Example Working Setup for React + Docker + Nginx
# Build stage
FROM node:18-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM nginx:stable-alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]nginx.conf snippet:
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets aggressively
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000";
}
# Cache favicon for 1 day only
location = /favicon.png {
expires 1d;
add_header Cache-Control "public, max-age=86400";
}
location = /favicon.ico {
expires 1d;
add_header Cache-Control "public, max-age=86400";
}
# Disable caching for HTML to enable quick updates
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
}And in your index.html:
<link rel="icon" type="image/png" href="/favicon.png?v=2" />Final Notes
- Always bump the query parameter version (
?v=2,?v=3…) when updating the favicon. - Use browser dev tools (Network tab) to verify favicon requests and headers.
- Purge CDN caches after deployment to avoid stale content.
- For multiple favicons (e.g.,
.ico,.png), update all and reference accordingly.