Caching looks simple enough on paper. Then you start building something real, and the questions pile up fast.
Should your product images come from the cache?
Should your shopping cart always hit the server?
Is it fine to serve data that’s a little stale if it makes the whole thing feel noticeably snappier?
Sooner or later, most web apps lean on one of three caching strategies:
- Cache First
- Network First
- Stale-While-Revalidate (SWR)
Learning what each one does takes an afternoon.
Working out when to reach for which is where the actual engineering starts.
So in this piece I want to walk through the trade-offs each one makes, and leave you with a mental model you can actually apply to your own apps.
The Mental Model
Forget implementation for a moment.
Underneath, all three are wrestling with the exact same question:
When a request arrives, where should I look first?
Should the application check the cache?
Or skip that and go straight to the network?
Or hand back what’s cached right away and quietly go fetch a fresher copy in the background?
Get that question straight in your head and the rest of it stops feeling so slippery.
Cache First
Cache First checks whether a resource already exists locally.
If it’s there, you get it back straight away.
If it’s not, the app goes and grabs it over the network, then tucks it into the cache so next time is quick.
Request
│
▼
Cache
│
┌────────────┴────────────┐
│ │
Found Not Found
│ │
▼ ▼
Return Fetch Network
The obvious win here is speed.
Pulling something out of the cache beats a round trip to the server almost every single time.
That's why Cache First works well for resources that rarely change.
Examples include:
- Company logos
- Images
- Icons
- Fonts
- CSS
- JavaScript bundles
When to avoid it
Don't use Cache First for information that users expect to be current.
Serving an outdated shopping cart or account balance might be fast, but it creates a poor user experience.
Network First
Network First takes the opposite approach.
Rather than reaching for the cache first, it goes to the server every time to pull the newest version.
If that call goes through, you get the fresh copy.
If the network’s down, it drops back to whatever’s in the cache instead.
Request
│
▼
Network
│
┌────────────┴────────────┐
│ │
Success Failure
│ │
▼ ▼
Return Cache
Fresh
The goal isn't speed.
It's correctness.
Network First is a good fit for data that changes frequently, such as:
- Shopping carts
- Notifications
- Account information
- Inventory
- Order status
- User permissions
The trade-off
The user might wait a touch longer, but what lands in front of them is the most current data you’ve got.
When getting it right beats getting it fast, that’s a trade worth making.
Stale-While-Revalidate
Stale-While-Revalidate (SWR) is the middle path between those two.
Rather than picking speed or freshness, it tries to give you a bit of each.
When a request arrives:
- Return the cached version immediately.
- Go fetch the newer version in the background.
- Swap the fresh copy into the cache for next time.
Request
│
▼
Return Cached Data Immediately
│
▼
Fetch Latest Version
│
▼
Update Cache
To the person using it, the app feels basically instant, and it’s quietly keeping itself current at the same time.
It’s a great fit for things like:
- Product listings
- Blog articles
- Documentation
- News feeds
- Search results
- Social timelines
The trade-off
For a moment, someone might be looking at slightly old content before the fresh version swaps in.
For a lot of apps, that’s a perfectly fine trade.
For anything touching banking or payments, it usually isn’t.
Choosing the Right Strategy
Don’t bother memorising definitions. Just ask yourself a couple of questions instead.
Does this resource rarely change?
Use Cache First.
Examples:
- Images
- Fonts
- Logos
- Icons
- Static assets
Does it always need to be current?
Use Network First.
Examples:
- Checkout
- Shopping cart
- User permissions
- Payment status
- Inventory
Is slightly outdated content acceptable if the application feels much faster?
Use Stale-While-Revalidate.
Examples:
- Product catalogues
- Blogs
- Documentation
- Search
- News feeds
A Practical Cheat Sheet
| Resource | Recommended Strategy |
|---|---|
| Company logo | Cache First |
| Product images | Cache First |
| Fonts | Cache First |
| Product catalogue | Stale-While-Revalidate |
| Search results | Stale-While-Revalidate |
| Documentation | Stale-While-Revalidate |
| Shopping cart | Network First |
| Checkout | Network First |
| Payment status | Network First |
| Account balance | Network First |
Common Mistakes
Using one strategy everywhere
Not every resource wants the same thing.
An image, a payment, a notification, a set of search results — treating all four the same way is asking for trouble.
Optimising for speed instead of user expectations
Faster isn’t automatically better.
Flashing someone a stale account balance is a far bigger problem than making them wait one more second for the real number.
Forgetting that caches become stale
Caching was never only about stashing data somewhere.
It’s just as much about deciding when that data has gone off.
Whatever you cache, have a plan for how and when it gets refreshed or thrown out.
Engineering Takeaways
If only a handful of this sticks, make it these:
- Cache First prioritises responsiveness.
- Network First prioritises correctness.
- Stale-While-Revalidate balances responsiveness and freshness.
- Different kinds of data call for different caching strategies.
- Optimise for what the user expects to see, not just for a green number on a dashboard.
One Thing to Remember
Every caching strategy is a trade-off. What decides the right one isn’t the tool in your hands — it’s what your users expect from the data they’re asking for.
Once caching clicks into that frame, picking between Cache First, Network First, and Stale-While-Revalidate stops being a guessing game.
If you want to go deeper, I’m putting together a much fuller guide right now — browser caching, HTTP caching, Service Workers, PWAs, and the architectural calls that sit behind modern frontend caching.

Top comments (0)