A Guide to HTTP Cache Control Headers
Cache Control Headers are a powerful tool for controlling how browsers and caches store and serve your website's content. By setting the right headersyou can improve your website's performanceand in some caseshave your users experience near-instant page loads.
HTTP Cache-Control Headers
Caching improves website performance. A well-implemented caching strategy reduces bandwidth usageserver loadand page load times. At the heart of HTTP caching is the Cache-Control HTTP headerwhich gives you fine-grained control over how browsers and intermediary proxies cache your content.
This guide explains the most common Cache-Control headerstheir practical applicationsand provides real-world examples for different scenarios.
The screenshot below shows an example of the cache control header value for different URLs. You can test your own site with our free website speed test.

This article provides an overview of HTTP cache control headers.
Do you want a more comprehensive guide on browser caching? Check out our How To Leverage Browser Caching to Improve Site Speed post.
Introduction to HTTP Caching
HTTP caching works by storing copies of resources (like HTML pagesimagesor scripts) closer to the user – either in their browser or in intermediate caches like proxies and Content Delivery Networks (CDNs).
When a user requests a resource that is cachedthe cached copy can be served without hitting the origin serverresulting in faster response times and reduced server load.
The way a resource is cached is controlled primarily through HTTP headerswith the Cache-Control header being the most important one. Expires headers were also widely used in the past.
You can specify one or more directives within the Cache-Control header.
For exampleCache-Control: max-age=3600public sets a maximum cache duration of 1 hour and allows the resource to be cached by any cache. Howeversome examples below show only one directive for simplicity. In practiceyou can combine multiple directives to create more customized caching strategies.
How to view cache-control headers for a resource on your website
If you want to check how your website uses the cache-control header to specify browser caching behavioryou can run a free website speed test with DebugBear.
The request waterfall view lists all the resources loaded by your website. You can click on each one and open the Headers tab to see what response headersincluding cache-controlwere sent by the server.

You can also enable the "Cache Control" column to view cache settings for all resources.
Use no-store when you don't want any caching
What it does: The no-store directive instructs browsers and caches to not store any version of the resource. It is suitable for sensitive data or regularly changing data that you don't want to be cached.
Cache-Control: no-store
Example URLs:
/dashboard: Has sensitive user data that updates frequently./account/bank-balance: Shows the user's bank balance; this should never be cached./api/stock-prices/GOOG: The current stock price of Googlewhich can change frequently.
When to use: Apply this header to pages containing personal or sensitive informationsuch as account pagescheckout flowsor anything containing PII (Personally Identifiable Information). Also useful for real-time data that needs to always be freshlike stock prices or live sports scores.
Use no-cache for content that requires validation
What it does: The no-cache directive doesn't mean "don't cache" – it means:
You can cachebut you must revalidate with the server before using the cached copy.
Cached resources must be validated with the origin server before each reuseeven if they haven't expired.
Cache-Control: no-cache
Example URLs:
/news: Content that changes frequently but doesn't need real-time updates./products/popular: A list of popular products that updates regularly./weather/current: Current weather information that updates periodically.
When to use: Apply this header to content that changes frequently. It strikes a balance between ensuring relatively fresh content while potentially saving bandwidth when the resource hasn't changed.
Use private for user-specific content
What it does: The private directive specifies that the response is intended for a single user and must not be stored in shared caches like CDNs or proxies. It can still be stored in a browser's cache.
Cache-Control: private
When a cache duration (e.g. max-age) or revalidation directive (e.g. must-revalidate) is not specifieda browser or CDN will make their own decisions about caching based on the content type and other factors.
Example URLs:
/my-account/profile: User profile information./orders/history: User's order history./recommendations: Personalized content recommendations.
When to use: Apply this header to any user-specific content that shouldn't be shared with other users but can be cached in the user's browser. This is particularly important for content delivered after authentication.
Use public for shareable content
What it does: The public directive explicitly marks a response as cacheable by any cache. It's useful for content that is the same for all users and can be shared among them.
Cache-Control: public
Example URLs:
/about-us: Public information about your company./help/faq: Frequently asked questions page./blog/post-1: Blog posts that are the same for all users.
When to use: Use this for content that is not personalized and can be shared among all users. This is especially useful in combination with other directives like max-age.
Use max-age to control how long content is fresh
What it does: The max-age directive specifies the maximum amount of time in seconds that a resource is considered fresh. After this timethe browser will request a new copy from the server.
# Cache content for 1 hour (3600 seconds)
Cache-Control: max-age=3600
You may be wonderingif you don't specify private or publicwhat's the default? In most casesthe default is publicmeaning the response can be cached by any cache such as a CDN or proxy. Howeverboth public and private caches may use their own heuristics to determine caching behavior.
Example URLs:
/blog/post-1: Blog content that is relatively staticbut updated occasionally./images/logo.png: Company logo that rarely changes./css/s.css: CSS files that change infrequently.
When to use: Use this for resources that don't change often. The duration should be based on how frequently the content changes. For exampleuse a shorter duration for a news homepage (possibly 5-15 minutes) and a longer duration for static assets like images or JavaScript libraries – possibly daysweeksor even a year.
Use s-maxage for CDN-specific cache control
What it does: The s-maxage directive works like max-age but applies only to shared caches (like CDNs and proxies).
The following example sets a 10-minute cache duration for user browsers and a 1-hour cache duration for CDNs:
Cache-Control: max-age=600s-maxage=3600
Example URLs:
/api/public-data: Public API responses that can be cached differently for browsers and CDNs./images/hero-banner.jpg: Large images that benefit from longer caching at the CDN level./product-catalog: A product catalog that updates daily on the CDN but might need more frequent updates in the browser.
When to use: Use when you want different caching behaviors between user browsers and CDNs. This is often useful for reducing load on your servers by allowing CDNs to cache content longerwhile making sure browsers get somewhat fresher content.
Use max-age=0 to force revalidation
What it does: Setting max-age=0 forces the cache to revalidate the resource with the origin server on every request.
Cache-Control: max-age=0
Example URLs:
/status/system: System status information that needs to be current./api/stock-prices: Stock prices that update frequently./news/latest: Breaking news that should always be fresh.
When to use: This is similar to no-cache – one difference being that no-cache will always trigger revalidation with the serverwhile max-age=0 can allow a cache to use a stale response if the server is unreachable; howeverthis behavior is not guaranteed.
Use must-revalidate to prevent using stale content
What it does: The must-revalidate directive tells caches they must revalidate the resource with the origin server before using a cached copymeaning that stale content is never served.
This example sets a 1-hour cache durationmeaning that if the resource is fresh (within 1 hour)it can be used without revalidation. Howeverif it's stale (older than 1 hour)it must be revalidated with the server before use:
Cache-Control: max-age=3600must-revalidate
Example URLs:
/api/user-profile: User profile information that must be current./feed: Social media feed that should always be fresh./news/latest: Breaking news that should never be stale.
When to use: Apply this header to content where serving stale data could lead to problemssuch as outdated pricing or incorrect user information.
Revalidation doesn't always mean transferring the entire content again. The server can respond with a 304 Not Modified status codeindicating that the content hasn't changedand the cache can continue using the cached copy.
In such a casethe server only sends the headersnot the content. In additionthe browser will update the resource so the new Cache-Control headers are applied.
Use immutable for versioned assets
What it does: The immutable directive tells the browser that the content of the file will never changeso the browser doesn't need to revalidate it even when the user refreshes the page.
Cache-Control: publicmax-age=31536000immutable
Example URLs:
/assets/main.f4fa2b.: JavaScript file with a content hash in the filename./css/s.ae3f66.css: CSS file with a content hash in the filename./images/logo.v2.png: Versioned image file.
When to use: Use for static resources that include a fingerprint (hash) or version number in their URLensuring that any change to the content results in a new URL. This is perfect for resources that follow the cache-busting patternwhere each change creates a new file with a different name.
Use stale-while-revalidate for background updates
What it does: The stale-while-revalidate directive allows the cache to serve a stale response while it revalidates in the backgroundmaking the next response fresh without the user waiting.
Consider this example:
Cache-Control: max-age=604800stale-while-revalidate=86400
These directives define seven days as the maximum cache durationwith a one-day window for serving stale content while revalidating. This means:
- Content up to seven days old is considered fresh and can be served immediately without a network request.
- Content between seven and eight days old is considered stale and must be revalidated in the background.
- The fresh content that is fetched in the background will be used for future requests.
Example URLs:
/api/user-count: API response showing user counts that can be stale for a short period./widgets/sidebar: UI components that can be momentarily stale./data/stats: Statistics that don't need to be perfectly real-time.
When to use: Apply this header to resources where some staleness is acceptable to improve performance. The stale content is shown to the user immediately while a fresh copy is fetched in the backgroundproviding a good balance between performance and freshness.
Use privateno-cache for authenticated content
What it does: This combination ensures that user-specific content is not stored in shared caches and must be revalidated before useeven from browser cache.
Cache-Control: privateno-cache
Example URLs:
/account/settings: User account settings./messages/inbox: User's private messages./api/feed: Personalized content feed.
When to use: Apply this header to authenticateduser-specific content that changes frequently and shouldn't be shared with other users. This provides security while still allowing for efficient revalidation through the browser cache.
Use no-transform to prevent modifications
What it does: The no-transform directive prevents intermediaries (like proxies or CDNs) from modifying the content of the responsesuch as compressing images or transcoding media.
Cache-Control: no-transform
Example URLs:
/images/high-res/photo.jpg: High-quality images where quality shouldn't be modified./downloads/document.pdf: PDF files that shouldn't be modified./media/video.mp4: Video files that shouldn't be transcoded.
When to use: Apply this header to resources where any modification by intermediaries could negatively impact quality or functionalitysuch as high-resolution imagesor media files with specific encoding.
Use stale-if-error for resilience
What it does: The stale-if-error directive allows a cache to return a stale response when an error occurs during revalidation. This means that content remains available even if the server is temporarily unreachable.
This example sets a one-hour cache durationallowing the cache to serve stale content for up to 24 hours if the server is unreachable or returns an error during revalidation:
Cache-Control: max-age=3600stale-if-error=86400
Example URLs:
/api/product-recommendations: Product recommendations that could be stale during outages./common/footer: Site components that should remain available during partial outages./images/logo.png: Company logo that should always be available.
When to use: Apply this header to non-critical resources where having stale content is better than no content during server outages or maintenance.
Test cache-control headers with synthetic testing
If you want to see how fast your website loads with the right caching settings in placetry the warm load feature in DebugBear's synthetic website monitoring product.

You'll often find that pages load extremely fast if previously loaded resources can be re-used.
After the initial visitwebsites are usually much faster thanks to caching. The main page content can now render in just over half a second!

In the waterfallresources that are loaded from the cache are marked by a "cache" badge for the request.

Specify ETags and Last-Modified values
It's important to note that for caching to be effectiveyou also need to configure validators like ETags or Last-Modified headersespecially when using directives like no-cache that rely on validation.
Additionallya cache-busting strategy for static assets is key when implementing long-term caching. For exampleyou can include a unique content hash in the file name.
Optimize caching and overall website performance
By using the appropriate Cache-Control headersyou can improve your website's performance and user experience.
DebugBear can track your synthetic metrics over timeprovide industry benchmarks based on Google CrUX dataand collect real-user metrics and debug data on how actual visitors experience your website.

Real user Core Web Vitals metrics let you see how visitors really experience your website. DebugBear's RUM product lets you identify slow pages and debug requests and scripts that cause delays.
You can also track cache hit rates for resources on your website or measure conversion rates to see how performance impacts business results.



Monitor Page Speed & Core Web Vitals
DebugBear monitoring includes:
- In-depth Page Speed Reports
- Automated Recommendations
- Real User Analytics Data