Harnessing Client-Side Caching in Rails: The Power of `expires_in`

Ackshaey Singh
3 min readOct 5

In your journey as a software developer, you’ll encounter myriad tools and techniques designed to optimize and streamline web applications. One such tool, often overlooked, is client-side caching. As backend and full-stack engineers, we spend hours crafting complex caching layers on the backend. However, we often overlook the most effective caching technique: having the request never reach the backend! Let’s delve into how requests get cached on the client using the Cache-Control header.

Cache Control Header

At the core of client-side caching is the HTTP Cache-Control header. This header offers directives to browsers (and other caching agents) about how they should cache the content and when to consider it stale.

The most common directives include:

  • max-age: Specifies the number of seconds the response remains fresh.
  • no-cache: Directs caching agents to revalidate with the server before using the cached version.
  • public/private: public means that any cache, including CDNs, can store the response. private ensures the response is user-specific and only cached at the end-user level.

By setting the appropriate cache control headers, developers can steer the caching behavior of browsers and intermediaries, thereby optimizing both server load and user experience.

Rails expires_in in Controller Actions

In the Rails ecosystem, the expires_in method is our key to effortlessly managing the cache control header. Within the context of Rails actions, using expires_in sets the Cache-Control header on the HTTP response.

Take, for instance, an application like Designer Discount Club I’m currently building. The product data updates roughly once a day, and constructing the response requires complex queries and interactions with multiple services. Below, the display_cards action powers an infinite scroll list on the client. By implementing expires_in 1.hour, public: true, we essentially direct clients to retain and reuse their cached response for an hour. When users navigate back and forth, adding this cache control header reduces ~100ms round trip time from the client's perspective and diminishes request volume to our backend Redis cache by over 60%.

Ackshaey Singh

Founder @ firecode.io / designerdiscount.club | Ex Staff SWE / Manager @Opendoor | Ex @Twitter Ads Engineering