Cache HTTP headers

There are cache headers that can be used from the HTTP protocol when telling the browser if that content should be saved or not, and for how long.

NOTE: This article reviews the most interesting and applicable items. If you are interested in knowing in more detail other possibilities, please check the HTTP Headers in Web Docs.


The Age header should only be used if we have an intermediate cache, either something like Cloudflare or a web-proxy, Varnish type. All browsers support this header.

This header should indicate how long that object is cached, that is, the time from the current moment until it was cached.

The number indicated is in seconds.

An element that has been cached for an hour and a half would indicate such that:

Age: 5400


The Cache-Control header is sent to the browser from the server to indicate how that object should be cached in the browser itself. This header is supported by all browsers, although it has an experimental element that only Firefox supports (then I detail it).

This element has several possible parts (not all of them should always be used).


In addition to the browser’s own cache, a few different things can be forced.

For example, by default, a request under HTTPS should not be cached, but since today most traffic travels over HTTPS, we may want them to be cached. A simple but clarifying example is that of the logo of the page, which will probably be used everywhere… and therefore we should frisk it.

In the same way, there may be some element that we want to cache but only for that user and in that session. This request would be private.

If we want an item not to be stored in the cache, we must tell it not to be stored specifically. An example could be, for example, an image of a captcha, or that of a PDF with bank details.

Some examples of these cases would be:

Cache-Control: public;
Cache-Control: private;
Cache-Control: no-store;

It is important to note that the option no-cache does not mean that it will not be stored, but that if there is a cached version it must be revalidated with the server.

In short, with these elements, we tell the browser where the information should be stored.


When we store something in the browser’s cache we should report how long that information should last, or leave a data with which to calculate when it has been saved.

As a general rule, we will tell you how long that element should be in the cache, the maximum time. In this case we will indicate the seconds that will be.

As a general rule, this time is defined according to the type of file. For example, images can usually be saved for months, but a file that can be modified, minutes or hours.

Cache-Control: max-age=3600;

But, also for our security, we could tell the browser what happens if a content is obsolete, and a new version cannot be recovered from the server.

In the same way as the previous case, we could indicate this element depending on the type of content.

Cache-Control: max-stale=3600;

In the same line, we can also force how often this element should be refreshed, even if we have the previous data included.

Cache-Control: min-fresh=600;

Validation and recharge

The third of the elements that we could indicate is how this element that we want to cache and what to do in certain cases.

One option would be to indicate that an item should be updated again once the expiration date has passed (complying with the other possible rules). In this case, we must inform that it must be validated again.

Cache-Control: must-revalidate;

Otherwise, we may have some elements that we know will never change. Especially if when we upload an element we do not overwrite it but version it in some way, so we have all the versions in different files. In this case those elements are immutable.

Cache-Control: immutable;

Some cases and examples

If we want an item not to be saved in the user’s browser, we will simply launch this header:

Cache-Control: no-store;

But if we want, for example, a logo to be stored, and that file is not going to be changed, we could launch something like this:

Cache-Control: public, max-age=2419200, immutable;

This by default would store that file for 1 month and use it without revalidation.


On occasion we need a user’s browser cache to be emptied. How to get it from our own website? Well, with this header we can indicate certain elements that can be sent to be eliminated.

This header mainly allows you to delete 3 elements (or all), which are the cache, cookies or storage.

One of the elements is the cache, and if we want to empty everything there is we can send the corresponding header.

Clear-Site-Data: "cache";

In the same way we can delete all cookies from the site.

Clear-Site-Data: "cookies";

And finally what is stored in the storage system (which is not the cache itself) such as the localStorage or the IndexedDB

Clear-Site-Data: "storage";

Although we can also ask you to remove combinations of various elements.

Clear-Site-Data: "cache", "cookies";

Or we can tell you directly to remove all the components, with an asterisk.

Clear-Site-Data: "*";

For example, when you log out of a page, we could delete all cached material. For WordPress, at least until WordPress 5.7 doesn’t come natively, so you can use the Clear Logout plugin.


If we know when a piece of content is going to expire instead of reporting how long a cached item has been, we can tell you directly when we want that content to disappear from the browser cache.

This element, if the Cache-Control exists, is rendered unusable.

Expires: Wed, 21 Oct 2015 07:28:00 GMT


Although in itself it is not a cache system, it is a complementary element to caches, since it would be a unique identifier of a content, a kind of digital unique identifier of a content at a specific time and that is usually based on several elements of the file itself, such as date or size (among other things).

Thanks to this system it will give a little equal the time that an element is cached, since what will be done is to validate if it is the same element or not, and in case the identifier of that component (image, PDF, etc …) changes, then only at that moment the request will be made to call and update again from the server.

ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"


Although it is not a cache header, it does help to have one or more caches as we want to define.

The idea is that, for example, the same URL has different files or caches according to some value. A common example is usually whether a page is for desktop or mobile, and may have headers with this style:

X-Device: desktop;
Vary: X-Device;

In this way, for each different X-Device that we have, a different cache will be generated in the browser.

Keep in mind that not all web servers allow this normalization of data or injection of values, so it is necessary to analyze case by case so that no infinity of caches of the same file are generated.


Of all the browser caching systems, the main one we should always use is cache-Control, especially when we talk about static elements such as CSS, JavaScript, texts (txt) or images.

For dynamic content, it will depend a lot on whether we want to have a system that allows us to maintain cacheable elements, especially if we talk about a high-traffic site that is saturated and we prefer to show obsolete elements than server errors.

About this document

This document is regulated by the EUPL v1.2 license, published in WP SysAdmin and created by Javier Casares. Please, if you use this content in your website, your presentation or any material you distribute, remember to mention this site or its author, and having to put the material you create under EUPL license.