Cache lab · Intermediate · 15 min
How to set up browser caching — Cache-Control: Long Lifetimes, Safe Invalidation
A returning visitor should download almost nothing — which is only safe once every long-lived asset carries a version in its URL.
The short answer
Give fingerprinted assets a long max-age with immutable, give images and fonts months, and give HTML no lifetime at all — then make sure every long-lived URL contains a version string, because that is what lets you ship a change on day two of a one-year cache.
Verify in the network panel rather than by refreshing. A repeat visit should show assets served from disk cache with no request at all; a 304 means the browser did ask and got nothing back, which is better than a full download but still a round trip you did not need to spend.
By the HostingFast team · Reviewed 24 August 2026
Intermediate
Assumed level
5
Stages to done
Free
Support cost
Proven
Verified on production
Fifteen minutes. The browser-cache option in LiteSpeed Cache writes sensible headers for you, and the manual .htaccess route exists for anything it does not cover.
The subtlety worth the time is invalidation. Caching is easy; invalidating is where sites end up serving last month's stylesheet to loyal visitors.
The header, field by field
Cache-Control is the one that matters. max-age sets the lifetime in seconds. public allows shared caches to store it, private restricts it to the visitor's own browser. immutable tells the browser not to revalidate even on a reload, which is exactly right for a file whose URL changes whenever its content does. Expires is the older equivalent and is still widely emitted alongside; where both are present, Cache-Control wins.
HTML is the exception to everything. Give a page a long lifetime and you have taken away your own ability to publish, because visitors will keep the stale copy for as long as you told them to. HTML gets no-cache or a very short lifetime, and its caching is handled server-side by LiteSpeed where you retain a purge control.
Lifetime by asset class
Fingerprinted CSS and JavaScript, and web fonts: a year, with immutable. Their URLs change when their contents change, so a long life carries no risk. Images: months is comfortable, since they are rarely edited in place. Anything with a stable URL and changeable content: short, or nothing.
The browser-cache option in LiteSpeed Cache applies a reasonable set across the standard asset types without you writing a line. Read the result back rather than trusting it: curl -sI https://example.com/wp-content/themes/your-theme/style.css | grep -i cache-control.
Invalidation is a URL problem
A cache lifetime is a promise you cannot revoke. Once a visitor has stored style.css for a year, nothing you do on the server reaches them — the browser will not ask. The only way out is to change the URL, which is why versioning exists: a hashed filename, or the ?ver= query string WordPress appends to enqueued assets.
So the rule is conditional: long lifetimes are safe only where the URL is versioned. If you have hand-written asset tags with stable filenames, either add a version to them or shorten the lifetime. Setting a one-year max-age on an unversioned stylesheet is how a site ends up looking broken for its most loyal readers and fine for everyone else.
The two states people confuse
In the network panel, from disk cache or memory cache means no request was made at all — the browser used its stored copy, and that is the outcome you are optimising for. A 304 Not Modified means the browser did make a conditional request and the server confirmed nothing had changed: no body was transferred, but the round trip still happened.
On a high-latency mobile connection those round trips add up quickly, which is why the goal is from-cache rather than 304. And test with a normal repeat visit, not a hard refresh: a hard refresh deliberately bypasses the cache you are trying to observe.

The caching layers on this platform
LiteSpeed caching is built into the server on every plan, and its browser-cache option writes the client-side headers as well — so page caching and asset lifetimes are configured from one place.
Redis object caching is available for the query-level layer, and NVMe SSD storage sits behind all of it on every tier.
- Each Cache-Control directive explained by effect
- Lifetimes given per asset class, with reasons
- Versioning treated as the precondition for long caches
- Engineers who will read your headers with you
Why HostingFast
Standard on every plan
Directives, not recipes
max-age, public, private and immutable explained by what each does, so you can set a lifetime you understand.
Lifetimes by class
Fingerprinted assets, images, fonts and HTML each get a recommendation and the reasoning behind it.
The precondition stated
Long caches are safe only on versioned URLs, which is the sentence that prevents the classic stale-stylesheet incident.
Verification by header
curl against a real asset, so you know what you are sending rather than what the settings page implies.
304 versus from-cache
The distinction that separates a real win from a round trip you are still paying for on every repeat visit.
One place to configure
LiteSpeed handles both the page cache and the browser-cache headers, so the two layers do not drift apart.
Quick Start
From order to online
- 1
Read back the headers you send today
curl -sI https://example.com/path/to/style.css | grep -iE 'cache-control|expires'. Do the same for an image, a font and an HTML page. Four commands and you know your current position exactly.
- 2
Let the cache plugin write the rules, then verify
The browser-cache option in LiteSpeed Cache covers the standard asset types sensibly. Turn it on, then re-run the curl checks — configuration you have not observed in a response is configuration you are assuming.
- 3
Write the manual block only for what is left
In .htaccess, group by file type: long with immutable for fingerprinted CSS, JavaScript and fonts, months for images, nothing for HTML. Add one class at a time and test each, because .htaccess failures are all-or-nothing.
- 4
Confirm every long-lived URL is versioned
Hashed filenames or a ?ver= parameter. WordPress adds one to enqueued assets; hand-written tags usually have none. Anything unversioned gets a short lifetime instead, not a long one and a hope.
- 5
Test as a returning visitor, not with a hard refresh
Load the page, navigate away, come back. Assets should register as from disk cache rather than as 304s. A hard refresh bypasses the cache by design and will always show you a full download.
Built In
Loaded onto every plan
- LiteSpeed caching in the server, with a browser-cache option included
- NVMe SSD storage behind that cache on every tier
- Redis object caching available for the query-level layer
- .htaccess honoured with Apache-compatible semantics for manual rules
- Free SSL on every plan, so HTTP/2 asset delivery is available
- Built-in WebP image optimisation at no extra cost
- Full SSH access with Git and Composer for header verification over curl
- Staging environments for testing header changes before they ship
- Money-back cover: 30 days on hosting plans, 7 on reseller
- Human support on duty every hour of every day
Frequently Asked
What people ask us most often
What is the difference between a 304 and from disk cache?
From disk cache means the browser made no network request at all: it had a copy inside its declared lifetime and used it. A 304 means the browser asked whether its copy was still valid and the server said yes, transferring no body but spending a full round trip. Both avoid downloading the file; only the first avoids the latency. On mobile connections that difference is the bulk of what long lifetimes buy you.
Is a one-year max-age safe on a stylesheet?
Only if the URL changes when the file does. With a hashed filename or a version query string, a year is not merely safe but ideal, and immutable makes it stronger still. With a stable filename such as a plain style.css, a year is a trap: visitors who cached it will keep the old design until the lifetime expires, and there is nothing you can do from the server to reach them. Version the URL first, then extend the lifetime.
Does browser caching help a first-time visitor at all?
Not on their first page — nothing is stored yet. It helps from their second page view onwards, which is most of a session: the shared CSS, JavaScript and fonts are already local, so each subsequent navigation transfers only the HTML. Given that the majority of page views on most sites are not first views, the aggregate effect is large even though the headline first-load number does not move.
Should HTML ever carry a max-age?
Almost never in the browser. A cached HTML page means a visitor who cannot see your update and whom you cannot reach, which trades a small saving for losing control of your own publishing. Cache HTML on the server instead, where LiteSpeed holds it and you keep a purge button. A very short lifetime — measured in seconds — is occasionally justified for a page under extreme load, and that is the exception rather than the pattern.
Keep reading
How to Take Payments Online
Take card payments on a checkout path that is deliberately kept out of the cache.
How to Put WordPress in Maintenance Mode
Take the site off the air properly, with the right status code while you work.
Best Hosting With Redis Object Caching
Object caching for the queries a page cache can never help with.
Dedicated Servers
A whole machine, its resources uncontended and its caching layers yours to tune.
Business Hosting
More cores, more RAM and priority support for a site under real load.
Changing hosts? Run through our checklist first.
A straightforward sequence for a switch your visitors never feel: which files move first, how to shift email across without losing a single message, the right moment to repoint DNS, and the two mistakes behind almost all the downtime we get asked to rescue.
Both cache layers in one panel.
LiteSpeed page caching and browser-cache headers together, Redis object caching available, NVMe underneath, and engineers reachable at any hour.
View Dedicated Servers plans