Sign up ×
Webmasters Stack Exchange is a question and answer site for pro webmasters. It's 100% free, no registration required.

Confession: sites I maintain have different rules for Cache Control mostly based on the default configuration of the server followed up with recommendations from the Page Speed & Y-Slow Firefox plug-ins and the Network Resources view in Google's Speed Tracer. Cache-Control is set to private/public depending on what they say to do, ETag's/Last-Modified headers are only tinkered with if Y-Slow suggests there is something wrong and Vary-Accept-Encoding seems necessary when manually gziping files for Amazon CloudFront.

When reading through the material on the different options and what they do there seems to be conflicting information, rules for broken proxies and cargo cult configurations. Any of the official information provided by the analysis tools mentioned above is quite inaccessible as it deals with each topic individually instead of as a unified strategy (so there is no cross-referencing of techniques).

For example, it seems to make no sense that the speed analysis tools rate a site with ETag's the same as a site without them if they are meant to help with caching.

What are the hard and fast rules for a platform agnostic Cache Control strategy?


A link through Jeff Atwood's article explains Caching in superb depth.

For the record though here are the hard and fast rules:

If the file is Compressed using GZIP, etc - use "cache-control: private" as a proxy may return the compressed version to a client that does not support it (the browser cache will hold files marked this way though). Also remember to include a "Vary: Accept-Encoding" to say that it is compressible.

Use Last-Modified in conjunction with ETag - belt and braces usage provides both validators, whilst ETag is based on file contents instead of modification time alone, using both covers all bases. NOTE: AOL's PageTest has a carte blanche approach against ETags for some reason. If you are using Apache on more than one server to host the same content then remove the implicitly declared inode from ETags by excluding it from the FileETag directive (i.e. "FileETag MTime Size") unless you are genuinely using the same live filesystem.

Use "cache-control: public" wherever you can - this means that proxy servers (and the browser cache) will return your content even if the rest of the page needs HTTP authentication, etc.

share|improve this question

2 Answers 2

up vote 8 down vote accepted

First, don't get rid of the ETag like Yahoo says, unless you're using a server farm/cluster. As long as the same file always returns the same ETag when it hasn't changed, then it's a very useful directive.

As for other headers, Yahoo's best practices suggests to set a far future Expires header for static files, use Cache-Control for dynamic content. However Cache-control is perfectly fine for static content (pretty much no difference between them).

When you change cached static files you will need to change the filename, or add a unique parameter to the end, e.g. Changing the actual filename is preferred though, as noted in the comments below.

Incidentally, you can edit the YSlow rules to your liking, to remove the Etag rule and add your own domain as a CDN. This article is also a good read: Yahoo's Problems Are Not Your Problems

share|improve this answer
The ETag one made sense in Apache by doing "FileETag MTime Size" instead of the default which includes the inode (per FS so non-reliable) on Y-Slow. However the recommendations on Yahoo's best practices are a little confusing when compared to Page Speed's. For instance it says to use Cache-Control only on dynamic pages (as you too suggest), yet Google suggest using Cache-Control: public on static CSS and Cache-Control: private on manually GZipped Amazon Cloudfront files. – Metalshark Jul 22 '10 at 10:34
It's difficult to know what to make of that advice for proxies. Google just says "Some public proxies have bugs..." but it doesn't say how prevalent this is. It does advise to set the header Vary: Accept-Encoding, see the bottom of – DisgruntledGoat Jul 22 '10 at 12:00
Adding a query parameter disables caching of that file completely in some browsers. So you might want to go with the "change the file name" approach instead, like – Evgeny Jan 6 '12 at 7:19
@Evgeny: Which browsers? I heard this before but I've never seen a browser that actually doesn't cache the file (especially if you have the right headers). – DisgruntledGoat Jan 6 '12 at 13:57
@DisgruntledGoat actually, after some digging it seems that it is a relic from the http/1.0 era where it was part of the spec that actually said user agent must not cache assets that have query strings. On the other hand, states that it is the proxies (squid < 3.0) that will not cache assets and thus using query strings for cache busting is discouraged. – Evgeny Jan 7 '12 at 2:19

Change the request headers of your resources to use caching For most people, the way to ebable caching is to add some code to a file called .htaccess on your web host/server.

This means going to the file manager (or wherever you go to add or upload files) on your webhost.

The .htaccess file controls many important things for your site. If you are not familiar with the .htaccess file, please read my working with .htaccess article to get some know how before changing it.

The code below tells browsers what to cache and how long to "remember" it. It should be added to the top of your .htaccess file.

<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType text/html "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType text/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 1 month"

Save the .htaccess file and then refresh your webpage.


share|improve this answer
Nearly every example of ExpiresByType directives I see includes the mime-type text/x-javascript - is your server really responding with this content type?! (An example of blind copy/pasting IMO.) – w3d Sep 15 at 11:33

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.