How Browsers Cache Assets
Understand how browsers cache CSS, JavaScript, images, fonts and other web assets, how cache headers control reuse and how caching improves website performance.
Browser caching allows a web browser to store copies of previously downloaded resources and reuse them on later page loads. Instead of downloading the same CSS files, JavaScript bundles, images, fonts and other assets every time a page is opened, the browser can use a cached response when the caching rules allow it.
Effective browser caching reduces network requests, lowers bandwidth usage and can make repeat page loads significantly faster. It is one of the fundamental techniques used to improve web performance, especially for websites that serve many static assets.
What Is Browser Caching?
Browser caching is a mechanism in which the browser stores HTTP responses locally for potential reuse. When a page requests a resource that has previously been downloaded, the browser can determine whether the stored response is still usable or whether it needs to contact the server again.
Cached resources can include stylesheets, JavaScript files, images, fonts, videos and other HTTP resources. The exact behavior depends on HTTP response headers, the resource URL and the browser's caching rules.
First visit
↓
Browser requests asset
↓
Server returns asset + cache headers
↓
Browser stores response
↓
Later visit
↓
Browser checks cached response
↓
Reuse cached asset or validate it
↓
Asset becomes availableWhy Browser Caching Matters
Without caching, a browser may need to repeatedly download the same resources as a user navigates through a website or returns to it later. This increases network traffic and can make repeat visits slower than necessary.
- Reduce repeated network requests.
- Decrease bandwidth consumption.
- Speed up repeat page loads.
- Reduce server and CDN traffic.
- Improve responsiveness on slower connections.
- Allow static assets to be reused across multiple pages.
What Assets Can Be Cached?
Almost any HTTP resource can potentially be cached, although the appropriate caching policy depends on how frequently the resource changes and whether its response can safely be reused.
| Asset | Typical Caching Strategy |
|---|---|
| CSS | Long cache with versioned filenames |
| JavaScript | Long cache with versioned filenames |
| Images | Long cache when URLs are versioned or immutable |
| Fonts | Long cache for stable font files |
| HTML | Often shorter or revalidated more frequently |
| API responses | Depends on data freshness and application requirements |
How a Browser Decides Whether to Reuse an Asset
When a browser has a cached response, it does not simply assume that the response can always be reused. It considers the caching metadata associated with the response, including directives such as Cache-Control and validators such as ETag or Last-Modified.
The browser can generally follow one of several paths: reuse a fresh cached response without contacting the server, revalidate a stale response with the server, or download a new response when the cached resource cannot be used.
| Cache State | Typical Behavior |
|---|---|
| Fresh | Reuse cached response without validation |
| Stale but revalidatable | Contact server to check whether it changed |
| Not reusable | Download a new response |
The Cache-Control Header
Cache-Control is one of the most important HTTP response headers for controlling caching behavior. It allows servers to specify directives describing how responses may be stored and reused.
Cache-Control: public, max-age=31536000, immutableThe max-age directive specifies how long a response can generally be considered fresh, measured in seconds. For example, max-age=3600 represents one hour. The public directive indicates that the response may be stored by shared caches as well as private browser caches when other rules permit it.
Common Cache-Control Directives
| Directive | Purpose |
|---|---|
| max-age | Defines freshness lifetime in seconds |
| no-cache | Requires validation before reuse |
| no-store | Prevents storing the response |
| public | Allows shared caching when applicable |
| private | Restricts caching to private caches |
| must-revalidate | Requires validation when the response becomes stale |
| immutable | Indicates the response is not expected to change during its freshness lifetime |
Cache Freshness
A cached response has a freshness lifetime. While the response is fresh, the browser can often use it without sending another request to the origin server. Once the freshness lifetime expires, the response becomes stale and may need validation or replacement.
Asset downloaded
↓
Fresh cache period
↓
Reuse without validation
↓
Freshness expires
↓
Response becomes stale
↓
Revalidate or download againFreshness does not necessarily mean that the browser deletes the resource when the lifetime expires. A stale response can remain in the cache and may be revalidated with the server before it is reused.
What Is ETag?
An ETag is an HTTP response header that identifies a particular representation of a resource. Browsers can use it as a validator when checking whether a cached response is still current.
ETag: "asset-v42"When a cached response needs validation, the browser can send the ETag value back using the If-None-Match request header.
If-None-Match: "asset-v42"If the resource has not changed, the server can respond with HTTP status 304 Not Modified instead of sending the entire resource again. The browser can then reuse its cached copy.
Conditional Requests
A conditional request lets the browser ask the server whether its cached version is still valid. This can save bandwidth because the server does not need to transmit the complete asset when the cached representation remains current.
Browser
↓
"If-None-Match: asset-v42"
↓
Server checks current asset
↓
Asset unchanged
↓
304 Not Modified
↓
Browser uses cached copy| Response | Meaning |
|---|---|
| 200 OK | Server sends a representation |
| 304 Not Modified | Cached representation can be reused |
Last-Modified and If-Modified-Since
Another HTTP caching mechanism uses Last-Modified and If-Modified-Since. The server can provide a Last-Modified response header indicating when the resource was last changed.
Last-Modified: Mon, 24 Aug 2026 10:00:00 GMTDuring validation, the browser can send an If-Modified-Since request header. If the resource has not changed since the specified time, the server can respond with 304 Not Modified.
| Response Header | Request Header |
|---|---|
| ETag | If-None-Match |
| Last-Modified | If-Modified-Since |
ETag vs Last-Modified
Both mechanisms can validate cached responses, but they identify changes differently. ETag uses an identifier chosen by the server for a particular representation, while Last-Modified relies on a modification timestamp.
| ETag | Last-Modified |
|---|---|
| Representation identifier | Modification timestamp |
| Sent with If-None-Match | Sent with If-Modified-Since |
| Can distinguish representations precisely | Based on modification time |
| Useful for cache validation | Useful for cache validation |
Cache-Control and ETag Work Together
Cache-Control and ETag solve different parts of the caching problem. Cache-Control can determine how long a response can be considered fresh, while ETag can help validate a response after validation becomes necessary.
Cache-Control: public, max-age=3600
ETag: "homepage-v18"During the one-hour freshness period, the browser can normally reuse the cached response according to the cache policy. After that period, it may contact the server and use the ETag to determine whether the resource changed.
Caching Hashed Static Assets
Modern web applications often use content-hashed filenames for static assets. Instead of serving a file as app.js forever, a build system can produce filenames such as app.8f3a21.js. When the content changes, the generated filename changes as well.
app.8f3a21.js
app.91bd72.jsThis approach allows static assets to have very long cache lifetimes because a cached file can safely remain stored under its old URL. When the application changes, the HTML references a new filename and the browser requests the new resource.
Why Cache Busting Is Important
A major caching problem occurs when a resource has a long cache lifetime but its URL remains unchanged after the content changes. Some users may continue receiving the older cached version until the cache expires.
Cache busting solves this problem by changing the resource URL when the content changes. Content hashes are one of the most reliable ways to accomplish this for generated static assets.
| Strategy | Example | Typical Result |
|---|---|---|
| No versioning | app.js | Old cached copy may persist |
| Query version | app.js?v=42 | URL changes when version changes |
| Content hash | app.8f3a21.js | URL changes when content changes |
Long-Term Caching for Static Assets
Static assets with versioned or content-hashed URLs are strong candidates for long cache lifetimes. Because changing the content also changes the URL, a browser can safely keep an older version in its cache while new pages reference the new asset.
Cache-Control: public, max-age=31536000, immutableThis pattern is commonly used for production CSS, JavaScript, fonts and other immutable build artifacts. The exact policy should still match the application's deployment strategy and how URLs are generated.
Caching HTML Documents
HTML often requires a different caching strategy from static assets. HTML documents may reference the latest versions of CSS and JavaScript files, so keeping stale HTML for too long can cause users to receive outdated page structure or asset references.
For frequently updated HTML, a shorter freshness lifetime or revalidation strategy can be more appropriate. Static assets can then use much longer lifetimes when their URLs are versioned.
| Resource | Typical Consideration |
|---|---|
| HTML | May need frequent revalidation |
| Hashed JS | Can often use long-lived caching |
| Hashed CSS | Can often use long-lived caching |
| Versioned images | Can often use long-lived caching |
| Dynamic API data | Depends on freshness requirements |
Private and Shared Caches
A browser cache is a private cache associated with a particular user agent. Shared caches, such as intermediary proxies and CDNs, can store responses for reuse across multiple users when the response is suitable for shared caching.
This distinction matters when configuring Cache-Control. A response containing personalized or private information may require a different policy from a public static JavaScript file that is identical for every visitor.
| Cache Type | Typical Example |
|---|---|
| Private cache | Browser cache |
| Shared cache | CDN or intermediary proxy |
Browser Cache vs CDN Cache
Browser caching and CDN caching both reduce the need to retrieve resources from the origin, but they operate at different locations. Browser caching keeps resources on the user's device, while a CDN stores resources at distributed edge locations closer to users.
| Browser Cache | CDN Cache |
|---|---|
| Stored on user's device | Stored at edge servers |
| Can eliminate network request entirely | Can serve resource without reaching origin |
| Private to the browser | Can serve many users |
| Controlled through HTTP caching rules | Uses HTTP rules plus CDN configuration |
Caching Across Multiple Pages
One of the major advantages of browser caching is that a resource can be reused across multiple pages. If several pages reference the same stylesheet, JavaScript bundle, font or image, the browser may download it once and reuse the cached response on subsequent navigations.
Page A ──┐
├──> shared.css ──> Browser Cache
Page B ──┤
└──> shared.css ──> Reuse cached copyThis is particularly valuable for websites with shared layouts and common assets because the cost of downloading those resources can be distributed across multiple page visits.
Cache Invalidation
Cache invalidation is the process of ensuring that outdated cached content is no longer used when a newer representation should be delivered. It is one of the most important challenges in caching because an aggressive cache policy can make updates harder to deliver.
The most practical solution for static assets is often to avoid modifying a resource under the same long-lived URL. Instead, generate a new URL when the content changes and allow the old version to remain cached.
A good caching strategy makes old resources safe to keep and new resources easy to discover.
Common Cache Invalidation Strategies
| Strategy | Description |
|---|---|
| Content hashing | Generate a new filename when content changes |
| Versioned URLs | Change a version parameter when content changes |
| Short freshness | Allow resources to become stale quickly |
| Revalidation | Check whether the cached response is still current |
Common Browser Caching Mistakes
Caching problems often occur because a policy is applied uniformly to resources that have very different update requirements. Static assets, HTML documents, APIs and personalized responses should not necessarily use the same cache strategy.
- Using extremely long caching for unversioned assets.
- Confusing no-cache with no-store.
- Disabling caching for every resource.
- Caching personalized responses publicly.
- Lazy-loading or deferring critical resources without considering priority.
- Changing asset content without changing its URL when using long-lived caching.
- Ignoring cache behavior when deploying new application versions.
- Assuming a 304 response means the resource was downloaded again.
Best Practices for Browser Asset Caching
- Use long cache lifetimes for versioned static assets.
- Use content hashes for generated CSS and JavaScript files.
- Choose shorter or revalidation-based policies for frequently changing HTML.
- Use ETag or Last-Modified when conditional validation is useful.
- Do not use public caching for personalized responses unless it is safe.
- Keep Cache-Control directives consistent with the deployment strategy.
- Test caching behavior after production deployments.
- Combine browser caching with CDN caching where appropriate.
- Monitor cache behavior instead of relying only on configuration assumptions.
How to Inspect Browser Caching
Browser developer tools provide useful information about caching. In the Network panel, you can inspect individual requests, response headers, request headers, status codes and transferred data. This makes it possible to determine whether an asset was downloaded, validated or served from an existing cache.
Look for headers such as Cache-Control, ETag, Last-Modified, Expires and related request headers. Comparing the first page load with a subsequent reload can reveal whether static assets are being reused as expected.
| Header or Signal | What to Inspect |
|---|---|
| Cache-Control | Freshness and cache directives |
| ETag | Representation validator |
| Last-Modified | Modification timestamp |
| If-None-Match | ETag validation request |
| If-Modified-Since | Timestamp validation request |
| 304 Not Modified | Cached representation remains valid |
Example Caching Strategy
Consider a web application that produces hashed JavaScript and CSS files during its build process. The application can use a long cache lifetime for those immutable assets while using a more conservative policy for HTML.
# Static hashed assets
Cache-Control: public, max-age=31536000, immutable
# Frequently changing HTML
Cache-Control: no-cacheThe browser can keep the hashed assets for a long time because a new build produces different URLs when the files change. The HTML can be revalidated so that the browser can discover the newest asset references.
Frequently Asked Questions
What is browser caching?
Browser caching stores HTTP responses locally so the browser can reuse previously downloaded resources such as CSS, JavaScript, images and fonts instead of downloading them again whenever possible.
How does Cache-Control affect browser caching?
Cache-Control provides directives that control how responses may be stored and reused, including how long a response can remain fresh and whether it must be validated.
What is the difference between no-cache and no-store?
no-cache generally requires a cached response to be validated before reuse, while no-store tells caches not to store the response.
What does ETag do?
An ETag identifies a particular representation of a resource and can be used during conditional requests to determine whether a cached response is still current.
What does HTTP 304 mean?
HTTP 304 Not Modified tells the browser that its cached representation can still be used when the browser made a conditional request to validate the resource.
Why are hashed filenames useful for caching?
A content-hashed filename changes when the asset content changes. This allows the old URL to remain cached while the new application version references a new URL.
Should JavaScript files have a long cache lifetime?
Versioned or content-hashed JavaScript files are strong candidates for long-lived caching because changes produce new URLs. Unversioned files require more careful cache policies.
Is browser caching the same as CDN caching?
No. Browser caching stores responses on the user's device, while CDN caching stores resources at distributed edge servers. Both can reduce requests to the origin but operate at different locations.
Helpful HTTP and Caching Tools
A Cache-Control Generator helps create HTTP caching directives, an ETag Generator assists with creating ETag values for resource validation, an HTTP Header Generator helps construct common HTTP response headers, a CDN URL Generator creates URLs for CDN-hosted resources, and an HTTP Header Viewer helps inspect headers returned by web servers.
Conclusion
Browser caching is a fundamental part of web performance. By storing previously downloaded resources and reusing them when appropriate, browsers can reduce network traffic and make repeat page loads faster. Cache-Control determines important aspects of freshness and reuse, while ETag and Last-Modified can provide efficient validation when a cached response needs to be checked.
The most effective strategy is usually to give different resources different caching policies. Versioned static assets can often use long cache lifetimes, while HTML and dynamic data may require more frequent validation. When browser caching is combined with content hashing, responsive asset delivery, CDN caching and careful cache invalidation, websites can achieve faster and more predictable loading behavior.