Caching

When a visitor lands on a published site after the user made a change, the visitor should always see the latest version of the site. Caching the site for too long could unintentionally show content that was just hidden. Simply caching the site for a short time (eg 10-30 seconds) also doesn’t work because TTL clocks are per page. Even if Page A is refreshed and doesn’t show the hidden content, Page B will still show the hidden content until it is refreshed. We have to invalidate the entire site at once whenever there is a page edit.

A typical approach is to purge the site's cache via a platform like Cloudflare. But because Fernsage uses Supabase as the backend, any page edits go to the database via Supabase and not via our code and server. To make a request to Cloudflare to purge the cache, we would have to trigger the call whenever there is a database change. But because the database edit and external Cloudflare call are separate, they could fail independently. So we would also have to set up monitoring and retry infrastructure.

Instead, we are using a versioned cache key approach. Whenever there is page edit, a new cache key for that site is generated in the database. When a visitor lands on the site, Cloudflare checks the cache key and shows a new version of the site if there is a new cache key. While the cache key will last until the next page edit, Cloudflare is set to remember each cache key for up to 10 seconds only. Outside of the 10-seconds period, Cloudflare will ask for the cache key again. If the cache key is new, Cloudflare will fetch a freshly built version from our renderer (a Supabase edge function). So an edit will take at most 10 seconds to be reflected. If the cache key hasn’t changed, Cloudflare will serve from its cache.

This approach is more reliable for our architecture than purging via Cloudflare. The page edit and cache key generation happen (or fail) together in the database while page edit and an external Cloudflare call are separate.

Three more caching mechanisms:

  1. If the lookup for the cache key fails, Cloudflare will still serve the site but without any version number in the cache key. Since we can’t invalidate this version of the site by bumping the cache key, we cache it for only 30 seconds.
  2. The browser cache is set to 0 because we cannot invalidate the browser cache from our end and we don’t want the browser to cache and serve outdated content.
  3. The site, served with a versioned cached key, has a TTL of an hour, as a self-healing mechanism. In case there are any future bugs where a page edit doesn’t bump the cached key, the stale content will be shown for at most an hour.

A note on cost: With this approach, the cost scales with edits rather than traffic. Edits invalidate the site and require rebuilding. More traffic increases the number of cache key lookups. But the lookups are capped at one every 10 seconds (per Cloudflare center with active traffic) and a lookup is about 100x cheaper than a rebuild. Given that a human user can only edit that quickly (or slowly) while traffic could spike, this keeps the cost structure low. And even if traffic spikes, the number of (cheap) lookups is capped.

Created July 10, 2026
Last edited July 10, 2026