GMax Mart
Home Services Pricing Portfolio FAQ Reviews Blog Support Careers Change Language

Website Speed

Browser caching explained: Cache-Control, ETags and expiry

By · · 6 min read
Browser caching explained: Cache-Control, ETags and expiry

When a visitor moves from your home page to your services page, their browser does not need to download your logo, stylesheet and fonts again. At least, it should not. Whether it does depends on a few lines of instructions your server sends with every file, known as HTTP caching headers. Get them right and repeat visits and page-to-page navigation feel close to instant. Get them wrong and visitors either download the same files over and over, or keep seeing an outdated page after you update it. This is browser caching explained without jargon overload: how the browser decides, what the key headers mean, and what each type of file should use.

How a browser cache works

The browser keeps a local store of files it has downloaded. For each new request, it goes through a simple decision:

  1. Do I have a stored copy? If not, download it.
  2. Is my copy still fresh? If the server said it can be reused for a certain time and that time has not passed, use it without contacting the server at all.
  3. If stale, can I check whether it changed? Ask the server; if unchanged, the server replies briefly and the browser keeps using its copy.
  4. If changed or not checkable, download the new version.

Step two is the fastest outcome, since no network request happens. Step three still makes a request but avoids downloading the file body. Everything about caching configuration is about pushing requests towards those two outcomes where appropriate.

Cache-Control: the main instruction

The Cache-Control response header tells browsers and any shared caches in between, such as CDNs and proxies, how to treat a file. It can hold several directives separated by commas.

max-age

Sets how long, in seconds, a response stays fresh. max-age=3600 means one hour; max-age=31536000 means one year. During that period, the browser reuses the file without asking.

no-cache

Despite the name, this does not forbid caching. It means "store it, but check with the server before each reuse". It pairs well with validators so unchanged files cost only a small response.

no-store

This is the one that truly forbids storing the response anywhere. Use it for sensitive data such as account pages, order details or anything containing personal information.

public and private

private allows only the visitor’s own browser to store the response, not shared caches. public explicitly allows shared caches like CDNs to store it too. Pages that differ per logged-in user should be private or no-store.

immutable

Signals that the file at this URL will never change, so the browser should not revalidate it even when the visitor reloads the page. It only makes sense for files whose name changes whenever their content does.

s-maxage

Works like max-age but applies only to shared caches, letting a CDN keep a copy longer or shorter than browsers do.

Expires: the older header

Before Cache-Control existed, servers used an Expires header containing a fixed date and time after which the file is stale. It still works, but if both headers are present, Cache-Control’s max-age takes priority. Expires also depends on clocks being in sync, which is one reason max-age replaced it. You will still see it in older server configurations and some hosting control panels.

Validation: ETag and Last-Modified

When a cached copy is stale, the browser can ask whether it is still valid rather than downloading everything again. It needs a validator for that.

ETag

An ETag is an identifier the server assigns to a particular version of a file, often derived from its content or modification details. The browser stores it and, when revalidating, sends it back in an If-None-Match request header. If the file has not changed, the server responds with status 304 Not Modified and no body. If it has changed, the server sends a normal 200 response with the new file and a new ETag.

Last-Modified

The server can also send the file’s modification date. The browser returns it in an If-Modified-Since header, and the same 304 or 200 logic applies. ETags are generally more precise, because timestamps can change without content changing, or vice versa within the same second.

A load-balancer gotcha

On sites served by several servers, some web server configurations generate ETags using details specific to each machine. The same file can then have different ETags on each server, causing unnecessary full downloads. Developers typically configure ETags to use content-based values or rely on Last-Modified instead.

What should and should not be cached

The right policy depends on how often a file changes and whether it is personal.

  • CSS and JavaScript with versioned file names: long max-age, such as one year, plus immutable.
  • CSS and JavaScript without versioning: shorter max-age or no-cache with an ETag, so updates reach visitors.
  • Web fonts: long max-age; they rarely change.
  • Images, logos and icons: long max-age if file names change when replaced; otherwise days rather than a year.
  • HTML pages for public content: no-cache with validation, or a short max-age, so edits and price changes show promptly.
  • Logged-in dashboards, carts, checkout and order pages: private, no-store.
  • API responses with personal data: no-store.
  • Downloadable PDFs such as price lists: moderate max-age, as they tend to be updated in place.

Checking your current caching headers

Open Chrome DevTools, go to the Network tab and reload the page. Click any file and look at the Response Headers for Cache-Control, Expires, ETag and Last-Modified. Reload again without disabling cache: files served from cache show "(memory cache)" or "(disk cache)" in the Size column, and revalidated files show a 304 status.

PageSpeed Insights also lists static files with short lifetimes under "Serve static assets with an efficient cache policy".

Putting a sensible policy in place

On Apache, caching headers are often set through mod_expires and mod_headers rules in the configuration or .htaccess file. On Nginx, the expires and add_header directives inside location blocks do the job. Managed platforms and CDNs usually expose the same settings in their dashboards. Start with static assets, confirm headers in DevTools, then review HTML and private pages separately.

Hosting plans differ in how much of this you can control. Our Linux hosting supports custom rules, and for tailored server configuration a VPS plan gives full access.

Frequently asked questions

What is the difference between browser cache and server cache?

Browser cache stores files on the visitor’s device to avoid repeat downloads. Server-side caching stores generated pages or query results on your server so it can respond faster. They complement each other.

Does browser caching help first-time visitors?

Not directly, since they have nothing stored yet. It helps from their second page view onward and on return visits, which is where it saves most time.

Why do visitors still see my old website after an update?

Their browser is likely reusing files that were given a long max-age without versioned names. Shorter lifetimes for HTML and versioned file names for assets prevent this.

Is it safe to cache pages with forms?

Public forms can be cached, but pages containing security tokens tied to a session, like many login or checkout forms, should not be shared from cache. Mark those private or no-store.

Read next

Thinking…