2HAASStart a project
All posts

Tech Tips

Client-side caching for API responses

Refetching the same data on every visit wastes time and bandwidth. HTTP cache headers, an in-memory cache and browser storage each solve a different part of the problem.

The 2HAAS team2 min read

A user opens your product catalogue, clicks into a product and comes back. The app fetches the whole catalogue again. Nothing changed in those ten seconds, but the user waits and your API does the work twice.

Caching on the client removes that repeat work. There are three layers, and it pays to use them in this order.

1. Let HTTP do the caching

The browser already has a cache. It only needs to be told what it may keep.

Cache-Control: public, max-age=300, stale-while-revalidate=60

This response can be reused for five minutes. For one more minute after that, the browser may show the old copy while it fetches a fresh one in the background.

This layer costs no client code, and it also works for CDNs. Use it for anything that is the same for every user.

2. Keep data in memory during the session

Within a single visit, a data library such as TanStack Query or SWR keeps responses in memory. Two components asking for the same data share one request, and returning to a screen shows the cached data immediately while it revalidates.

If your app fetches with plain useEffect calls, adopting one of these libraries is often the largest single improvement.

3. Persist across visits when it helps

For data that changes slowly, such as a catalogue or a list of countries, you can keep a copy in browser storage with an expiry time.

const TTL = 15 * 60 * 1000; // 15 minutes

async function getCatalog() {
  const cached = JSON.parse(localStorage.getItem("catalog") ?? "null");
  if (cached && Date.now() - cached.savedAt < TTL) return cached.data;

  const data = await fetch("/api/catalog").then((res) => res.json());
  localStorage.setItem("catalog", JSON.stringify({ data, savedAt: Date.now() }));
  return data;
}

Within fifteen minutes, the catalogue appears without a request.

Which storage for what

Storage Good for Keep in mind
HTTP cache Public, shared responses Controlled by response headers
Memory Data for the current session Gone on reload
localStorage Small, simple values Synchronous, a few megabytes, text only
IndexedDB Large or structured data Asynchronous, more code to write
Cache API Whole responses for offline use Usually paired with a service worker

The hard part: stale data

A cache is only useful if it is not wrong.

  • Give everything an expiry. No entry lives forever.
  • Invalidate after writes. When the user changes a record, drop the cached copy.
  • Version your keys. catalog:v2 makes old entries disappear when the data shape changes.
  • Never store secrets in web storage. Access tokens and personal data in localStorage can be read by any script running on the page.

The result

Used together, these layers make repeat visits feel instant and reduce load on the API. Start with the HTTP headers. They are the cheapest win, and often the only one you need.

Keep reading

  1. Tech Tips2 min read

    JavaScript performance: keep the main thread free

    A page can load fast and still feel slow. Batch DOM updates, debounce noisy events and break up long tasks to keep the interface responsive.

  2. Tech Tips2 min read

    WebP and AVIF: modern image formats with a fallback

    WebP and AVIF produce much smaller files than JPEG and PNG at the same visual quality. How to convert your images and serve them with the picture element.

  3. Guides2 min read

    Find performance bottlenecks with Chrome DevTools

    Stop guessing why a page is slow. Use the Network and Performance panels in Chrome DevTools to find the heavy files, long tasks and layout shifts that cost you speed.

Tell us what’s in the way.

A few lines is enough. You get a candid yes, a candid no, or a sharper question.

  • Working software in week four
  • A reply in one business day
  • Handover is the deliverable

Prefer email? [email protected]

The problem, who it is for, and what is in the way right now.

One business day to a real reply. No sales sequence, no call required.