Home / Articles / Web Development
Web Development

HTTP Caching on Websites: How to Speed Up Pages Without Serving Stale Data

Caching can make a website feel much faster, but incorrect configuration can display outdated data or leak sensitive information. Learn how HTTP caching works, strategies for its use, and preliminary steps...

Cache HTTP di Website: Cara Mempercepat Halaman Tanpa Menyajikan Data Kedaluwarsa

A slow website is not always caused by an underpowered server. Often, browsers and networks are simply re-downloading the same files repeatedly: logos, CSS, JavaScript, images, or unchanged API responses. This is where HTTP caching comes into play.

HTTP caching is a temporary storage mechanism that allows browsers, intermediary servers, or CDNs to reuse responses that have been previously received. When used correctly, caching can reduce load times, save bandwidth, and decrease server load. However, overly aggressive caching can cause users to see outdated data, while caching at the wrong endpoints can pose privacy risks.

Caching is more than just "storing files"

Imagine you frequently borrow the same book from the library. Instead of going to the library every time, you keep a copy on your desk. As long as the book hasn’t changed, you can read it directly. HTTP caching works on a similar principle.

When a browser requests a resource, such as /assets/app.css, the server can inform how long that resource can be reused. On subsequent visits, the browser does not need to re-download as long as the copy is still considered valid.

Caching can occur in several places:

  • Browser cache, which is storage on the user's device.
  • CDN or reverse proxy, which stores responses closer to visitors.
  • Application cache, such as query results or frequently used data on the server side.

All three can speed up a website, but each has different expiration rules and risks.

Understanding the Cache-Control header

The main caching settings for HTTP are usually sent via the Cache-Control header. This header instructs browsers and intermediary caches on how a response can be stored.

A simple example:

Cache-Control: public, max-age=3600

This means the response can be stored by public caches and is considered valid for 3,600 seconds or one hour. After that, the cache needs to check back with the server.

Some important directives include:

  • public: the response can be stored by public caches like CDNs.
  • private: the response can only be stored by the user's browser, not shared caches.
  • no-store: the response must not be stored. Suitable for highly sensitive data.
  • no-cache: the response can be stored but must be validated with the server before reuse.
  • max-age: the maximum duration, in seconds, before the response is considered expired.

The difference between no-cache and no-store can often be confusing. no-cache does not mean "do not store"; the browser can still store a copy but must request validation before using it. Meanwhile, no-store requests that the response not be stored at all.

Distinguishing static files from dynamic data

A common mistake in caching configuration is treating all responses with the same rules. Static files and personal data should have different policies.

Static files are suitable for long caching

Files like images, fonts, CSS, and JavaScript are generally safe to have a long cache duration, especially if their filenames use versions or hashes.

<script src="/assets/app.8f31c2.js"></script>

If the content of the JavaScript changes, the filename also changes. The browser will treat it as a new file and download the latest version. This pattern is called cache busting.

A common header for versioned assets looks like this:

Cache-Control: public, max-age=31536000, immutable

With this rule, the browser can store the file for up to one year. The immutable directive signals that the file will not change as long as its URL remains the same.

User data requires more caution

Responses such as user profiles, order histories, dashboard pages, and API results that depend on login sessions should not be carelessly stored by public caches.

Cache-Control: private, no-cache

For highly sensitive information, use:

Cache-Control: no-store

Practically, checkout pages, authentication tokens, account details, and health data require special attention. Do not rely solely on seemingly safe URLs. Also check cookies, authentication headers, and the content of the responses.

Validation with ETag and Last-Modified

Caching does not always require downloading the entire file when its validity expires. The server can provide version markers using ETag or modification times via Last-Modified.

ETag: "article-42-v3"
Last-Modified: Tue, 22 Sep 2026 09:30:00 GMT

When checking again, the browser sends these values through headers like If-None-Match. If the content has not changed, the server can respond with a 304 Not Modified status without resending the file's content.

The result is not only faster but also more bandwidth-efficient. This is particularly useful for large files that rarely change.

Common caching issues

Users still see old versions

This usually happens because the URL name remains the same while the file content changes. The solution is to add a version to the filename or query string, for example, app.css?v=4. For cleaner projects, use automatic hashes from the build process.

User data gets mixed up

This can occur if pages that should be private end up in public caches. Review the use of public, session cookies, and CDN configurations. User-based data generally needs to use private or no-store.

Changes are not immediately visible on the CDN

The CDN may still store an old copy even if the origin server has been updated. You need a purge or cache invalidation mechanism. However, do not make purging a solution for every deployment. Cache busting through filenames is usually more predictable.

What you can do now

  1. List all types of responses on the website: static assets, public pages, APIs, and personal data.
  2. Determine which can be safely stored long-term and which must always be validated.
  3. Add versions or hashes to CSS and JavaScript files.
  4. Use private or no-store for responses related to accounts and sessions.
  5. Check response headers using browser DevTools or commands like curl -I https://example.com/assets/app.css.
  6. Test after deployment: open pages as different users and ensure no content is mixed up.

A good cache is a predictable cache

The goal of caching is not just to make performance numbers look good. A good cache helps a website feel fast without sacrificing data accuracy and user privacy.

Start with a simple separation: static assets can be stored long if their URLs are versioned, while dynamic data must be validated or not stored at all. After that, measure the results and document the policies. With this approach, caching shifts from a source of mysterious problems to a controllable part of the website architecture.

– Rio Yotto @rioyotto