This article's content
Caching

A cache’s primary purpose is to increase data retrieval performance by reducing the need to access the underlying slower storage layer. Trading off capacity for speed, a cache typically stores a subset of data transiently, in contrast to databases whose data is usually complete and durable.

The cache can exist at browser, CDN, load balance or many other layers.

Cache control response header to disable cache in HTTP/1.1

Let’s assume you load a single page application. You can check whether the index.html got cached by checking the cache-control in the response header, using web developer tools by pressing F12 in the browser.

In general, a good solution to disable browser cache for HTTP/1.1 would be:

Cache-Control: no-store, must-revalidate

cache-control can have these values:

  • no-cache — This name is a bit misleading, because it will use a cached version, but it will also check if there is a newer version on the server by validating the file’s hash on every request
  • no-store — This will tell any cache system not to cache the file whatsoever
  • max-age=0 — This is also won’t cache the file
  • max-age=31536000 — This is not a good choice for an index.html. The value in the max-age represents seconds — in this case the file would be cached for a year
  • The directive must-revalidate is also recommended. When it is enabled, the cache must verify the status of stale resources before using them. Expired resources should not be used.

Pragma response header for disabling cache in HTTP/1.0 and IE6

The following header could be used to disable cache for HTTP/1.0 :

Pragma: no-cache
Expires: 0

The Pragma general-header field is used to include implementation-specific directives that may apply to any recipient along the request/response chain. When the “no-cache” directive is present in a request message, an application should forward the request toward the origin server even if it has a cached copy of what is being requested.

The Expires entity-header field gives the date/time after which the entity should be considered stale. A value of zero (0) or an invalid date format should be considered equivalent to an “expires immediately.”

Best practice setting

Overall, the following solution could be the strictest, and also should be accepted by most of the browsers:

Cache-Control: max-age=0, no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0

ETag response header

The ETag (or entity tag) HTTP response header is an identifier for a specific version of a resource. It lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content was not changed. If the resource at a given URL changes, a new Etag value must be generated. 

A typical use of the ETag header is to cache resources that are unchanged. If a user visits a given URL again (that has an ETag set), and it is stale (too old to be considered usable), the client will send the value of its ETag along in an If-None-Match header field:

If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

The server compares the client’s ETag (sent with If-None-Match) with the ETag for its current version of the resource, and if both values match (that is, the resource has not changed), the server sends back a 304 Not Modified status, without a body, which tells the client that the cached version of the response is still good to use (fresh).

Single page applications and caching

It is important to never cache your index.html file, otherwise users will see the old version of your application until the browser cache expires.

Use a bundler like Webpack to implement hashed versioned file names, that means each application-build will create files that are named differently if their content changed. This is also called Filename fingerprinting.

Use no-cache and max-age headers on your JS, CSS, and any other files that change frequently

About Author

Mathias Bothe To my job profile

I am Mathias, born 40 years ago in Heidelberg, Germany. Today I am living in Munich and Stockholm. I am a passionate IT freelancer with more than 16 years experience in programming, especially in developing web based applications for companies that range from small startups to the big players out there. I am founder of bosy.com, creator of the security service platform BosyProtect© and initiator of several other software projects.