I also recommend to not emit a Last-Modified header and use ETag instead for asset revalidation, this avoids edge cases such as newer files with identical content or clock mismatches between web servers which would cause unnecessary bandwidth consumption.įor revalidation (aka conditional requests) to work, responses must be served with one or both of the ETag or Last-Modified headers. In general I recommend to not emit an Expires header and rely instead on the more comprehensive Cache-Control header. Pragma - a hangover from HTTP/1.0, this should generally not be used in preference for Cache-Control except where HTTP/1.0 clients must be supported ( docs) Last-Modified - a timestamp which allows browsers to validate the freshness of cached assets ( docs) Some are more obvious than others!Įxpires - a date (in GMT) after which this asset may no longer be used from the browsers cache and must be re-fetched ( docs)Ĭache-Control - a combination of features in one header, including how long the resource can be cached by the client (in seconds) as well as whether proxies can cache it, whether to force revalidation and more ( docs)ĮTag - a string that uniquely identifies an asset version, generally a server-generated hash of the file ( docs) There are a number of response headers set by a web server or CDN which manage client-side caching. A summary of the logic to determine which caching headers are best in different scenarios. or ?v=123) and set a single caching header allowing the maximum cache duration of one year: Cache-Control : max-age=31536000, immutableįor non-versioned assets which may change, combine the Cache-Control header with an ETag for asynchronous revalidation in the client: Cache-Control : max-age=604800, stale-while-revalidate=86400įor HTML files, set a low TTL and private cache flags: Cache-Control : max-age:300, privateĭo not emit unnecessary caching headers (including ETag and Last-Modified) to prevent unexpected client and server behaviours. Use versioned assets wherever possible (e.g. Caching in proxies, load balancers and Content Delivery Networks (CDNs) adds some more complexity, and is not covered here. Note that the focus of this post is on client-side (or downstream) caching - in the client device. We'll also talk about invalidating caches and ensuring browsers use the correct assets at the correct time. In this post we will review what caching headers are available and when they should be used. Allowing a browser to use a cached asset can be considered risky - JS which falls out of sync with HTML, CSS which persists an old campaign style, personalised assets accidentally being shared between visitors. The reason that these headers are often misconfigured, or at least configured suboptimally, is often through a descent to lowest risk.
The fastest request is the one that is not made, and caching headers allow us to tell browsers when they can reuse an asset that they have already downloaded. Caching headers are one of those deceptively complex web technologies which are so often overlooked or misconfigured.