DEV Community

Cover image for Speeding Up Your Website Using Cloudflare Cache
Lilou Artz
Lilou Artz

Posted on • Originally published at pillser.com

Speeding Up Your Website Using Cloudflare Cache

Performance is critical for websites to rank in Google search results. Pillser implements a number of techniques to load and render pages quickly. However, nothing beats caching. In this post, I will share my experience with Cloudflare cache.

Cloudflare Cache

I chose Cloudflare Cache because I am already using Cloudflare for other things.

To use Cloudflare cache, I needed to:

  1. Enable Tiered Cache
  2. Enable Cache Reserve
  3. Add Cache Rules

Tiered Cache and Cache Reserve are not strictly necessary, but they enable more reliable and faster cache hits.

When you enable Cache Reserve, you are able to cache gigabytes of data. Meanwhile, Tiered Cache reduces the amount of servers that Cloudflare needs to hop through to serve your website, which improves performance, e.g. I saw cached response times go from 100ms to under 10ms when I enabled Tiered Cache.

Finally, you need to add Cache Rules to define which pages should be cached. For example, I only want to cache pages that are accessed by non-authenticated users (identified by the presence of a user_account cookie), and I only want to cache pages matching a specific URL pattern. Here is a rule that does just that:

(
  not http.cookie contains "user_account" and (
    http.request.uri.path eq "/" or
    starts_with(http.request.uri.path, "/supplements") or
    starts_with(http.request.uri.path, "/probiotics") or
    starts_with(http.request.uri.path, "/vitamins") or
    starts_with(http.request.uri.path, "/minerals") or
    starts_with(http.request.uri.path, "/brands")
  )
)
Enter fullscreen mode Exit fullscreen mode

I love that Cloudflare cache is so flexible. Their rules language is very powerful.

Cache by Device Type

You can enable options like Cache by device type if you are serving different content to different devices. Example: Pillser will render a different number of supplements per page depending on whether the user is on a mobile device or a desktop.

Once enabled, Cloudflare sends a CF-Device-Type HTTP header to your origin with a value of either mobile, tablet, or desktop for every request to specify the visitor's device type.

Utilize Strong ETags

The ETag HTTP response header is an identifier for a specific version of a resource.

Enable Respect strong ETags to ensure that the cache is invalidated when the content changes.

For this to function, you need to add a ETag header to the response. Fastify ecosystem has a plugin to automatically generate strong ETags.

Serve Stale Content While Revalidating (Not Working as Expected)

This is the only thing that I was not able to figure out.

My ideal behavior would be to cache products for a short period of time (e.g., 1 hour) and then serve stale content while revalidating.

I have therefore configured Edge TTL to Ignore cache-control header and use this TTL and set the TTL to 1 hour. This ensures that the cache becomes stale after 1 hour.

I have then left Do not serve stale content while updating disabled. This is supposed to make Cloudflare serve stale content while revalidating, but it does not seem to work.

I am still occasionally seeing content being served directly from the origin with cf-cache-status set to MISS. I would expect this to not happen, as the revalidation should happen in the background while the cache is being served. If you happen to know how to fix this, please let me know.

Lacking Features: Max Age for Stale Content

Another thing that I noticed is that Cloudflare will sometimes expire cached content based on Cache-Control headers. However, in the example of wanting to serve stale content while revalidating, I would expect that there would be a setting that allows me to explicitly say how long the content should be cached for regardless of the Cache-Control header, i.e., I would want to set max-age to several days, but require that Cloudflare revalidates the content every hour.

Effectively, I want to force Cloudflare to retain the cache beyond the TTL.

Purging Cache

Last but not least, I needed a way to purge the cache. Cloudflare provides several ways to purge the cache. However, I found that the API approach is the easiest to use:

import { config } from '#app/config.server';
import Cloudflare from 'cloudflare';

const cloudflare = new Cloudflare({
  apiEmail: config.CLOUDFLARE_API_EMAIL,
  apiKey: config.CLOUDFLARE_API_KEY,
});

const response = await cloudflare.cache.purge({
  files: ['https://pillser.com/'],
  zone_id: config.CLOUDFLARE_ZONE_ID,
});
Enter fullscreen mode Exit fullscreen mode

This allows me to automate the purging of individual product cache, e.g. when a product is updated.

Results

I ran latency tests from several locations and captured the slowest response time for each URL. The results are below:

URL Country Origin Response Time Cached Response Time
https://pillser.com/vitamins/vitamin-b1 us-west1 240ms 16ms
https://pillser.com/vitamins/vitamin-b1 europe-west3 320ms 10ms
https://pillser.com/vitamins/vitamin-b1 australia-southeast1 362ms 16ms
https://pillser.com/supplements/vitamin-b1-3254 us-west1 280ms 10ms
https://pillser.com/supplements/vitamin-b1-3254 europe-west3 340ms 12ms
https://pillser.com/supplements/vitamin-b1-3254 australia-southeast1 362ms 14ms

The results are consistent across multiple regions. It is clear that Cloudflare cache hugely improves the performance of the website, especially for users further away from the origin (US).

Top comments (0)