Skip to main content

Command Palette

Search for a command to run...

57 Days in: Caching on the Browser Client

Updated
4 min read
57 Days in: Caching on the Browser Client

While working on the Brandify frontend, I want to ensure the client is as performant as possible since working with 3D models is already taxing enough. To do so I thought that I should cache data where possible such as the images that I fetch from the backend so as to reduce the computation time of components and reduce time taken for network requests

Caching however is such a broad term used to mean storing data that is frequently used in an easily accessible location and turns out there are various mechanisms to accomplish this in our browsers. I'll go over the different forms of caching that are commonly used and that I found useful.

HTTP Caching

HTTP caching is a browser-level cache that adheres to the HTTP protocol. It stores server responses, mapped by the request used to obtain them. This is particularly handy for static resources like images, CSS files, and JavaScript files. The browser typically configures the cache based on the server's instructions provided in the Cache-Control header.

# Request

GET /styles.css HTTP/1.1
Host: example.com
# Response
HTTP/1.1 200 OK
Content-Type: text/css
Content-Length: 1240
Cache-Control: max-age=3600
ETag: "v1.2.3"
Last-Modified: Wed, 26 Feb 2026 09:00:00 GMT

body {
  background: #fff;
}

Above is an example of a browser request and a server response. The request serves as a key, and the response is the value stored in the cache. When a user makes the same request again, the browser checks the cache first. If the content is still fresh, it returns the cached value, saving time and avoiding another network request.

This cache, while client-side, isn't accessible to developers. The browser manages its operation, and even without server instructions via the cache-control header, it still caches responses based on its own implementation, known as Heuristic Caching. And although the browser adheres to server guidelines, users can adjust their browser settings, like disabling caching entirely.

Cache Storage ( Cache API )

Another browser-level cache is the cache storage, accessed through the Cache API. Like a HTTP cache, it stores HTTP request-response mappings, but the Cache API offers developers more control over caching strategies. You can choose to follow the server's cache-control header or set your own rules. This flexibility is especially handy for PWA and offline-first apps. Typically, the Cache API works alongside service workers, which act as client-side proxies. They read from the cache storage and decide whether to make a network request based on the cache policy.

The Cache API is also persistent, meaning your browser retains the data even after shutdown. This feature is incredibly useful for offline apps that might not have regular network access. For some developers, this capability is essential, while others might find it simpler to rely on the HTTP cache set up by the origin server.

Application-Level Caching

Application-level caching involves web apps storing data in memory, typically as JavaScript objects. It can be as straightforward as using a variable like const cache = {key : data} and adding some validation logic to decide when the stored data is outdated or needs reevaluation. While this type of caching is quite volatile and doesn't persist through page refreshes, it offers the quickest access.

Developers can create their own caching methods, but many libraries already handle data caching or provide tools for it. Let me share some examples from Tanstack Query and React, two libraries I use for Brandify's frontend.

Tanstack Query

Tanstack Query makes great use of caching to manage server state efficiently. When you use the useQuery hook to fetch data from a server, Tanstack Query caches the data for future requests of the same query. If there's a change in the server state through the useMutation hook, the cache is updated accordingly, especially if it's set to refresh data from a specific useQuery call. Developers also have the flexibility to set expiration policies for cached data, ensuring everything stays fresh and up-to-date.

React ( useMemo and useCallback )

The useMemo and useCallback hooks in React provide a more detailed caching approach. These are actually memoization techniques and the stored data only lasts as long as the components using them are mounted. UseMemo helps in saving the results of functions, while useCallback keeps a function definition from being recreated with every rerender. They're commonly used in React apps to boost performance.

Conclusion

Caching is an easy win for browser clients handling heavy assets like 3D models and large images. Start with sensible server cache headers, measure with DevTools, and add client-side caching only where it helps. Your users will notice.

100 Days of Code: Building Brandify

Part 1 of 3

In this series, I document my 100 Days of Code challenge where I design, build, and ship Brandify. I share weekly progress, technical decisions, setbacks, lessons learned, and engineering trade-offs from backend architecture to product thinking.

Up next

39 Days into Brandify: Authentication and Anonymous Workflows

Last week, I mainly focused on two parts of Brandify: authentication and the designer page. The goal of authentication is for the web application to authenticate itself using Keycloak, so it can access server resources without the server getting invo...