Skip to article body
A woman reaching up to a tall shelf of rolled linen in an old Cairo storeroom
A woman reaching up to a tall shelf of rolled linen in an old Cairo storeroom

Web Development · Process

Cache the Answers, Check the Ref

How our server caches Prismic for ten minutes and still shows a new post within seconds.

By Shehab Waleed, Founder, Cairo Studio 3 min read

Every page on our site asks Prismic a few questions: this page, the projects it shows, the settings for the menu. Asking on every request adds a network round trip to every page. Caching the answers raises the usual question of when to throw them away.

The ref answers that question

Prismic content is versioned. The API root returns the current master ref, and every query includes that ref in its URL. When anyone publishes anything, the master ref changes.

So a query URL with a ref in it can never become wrong. Asked again in an hour, it returns the same answer, because it describes the content as it was at that ref. Only one thing goes out of date: which ref is current.

Two lifetimes

Our Prismic client wraps fetch with a small cache keyed by the full URL. The lifetime depends on whether the URL carries a ref.

const REF_TTL_MS = 5_000;
const QUERY_TTL_MS = 10 * 60_000;

const ttl = new URL(url).searchParams.has("ref")
? QUERY_TTL_MS
: REF_TTL_MS;

When something is published, the next ref check, at most five seconds later, returns the new ref. Every query after that has a new URL, misses the cache and fetches fresh content. The old entries simply stop being asked for and fall out of the cache, which holds 300 responses.

Serve first, refresh behind

An expired entry is still returned straight away, and the refresh happens in the background. A visitor never waits for Prismic once a page has been seen. The cost is that the first visitor after an expiry gets the previous answer. For the ref that means at most a few seconds of old content, which we are happy with.

if (hit) {
if (hit.expires <= Date.now()) revalidate(url);
return new Response(hit.body, hit);
}

Failed responses are never stored, so a Prismic outage does not get cached as an empty page.

What we are less sure about

The cache lives in memory, in each server process. We run two, so each warms up on its own after a deploy. The limit of 300 entries is a guess that fits our page count, not something we measured.

There is also a second cache we do not control. Prismic’s CDN can keep serving the old ref for a short while after a publish. When our scripts check that a publish worked, they read the origin host, cairo-studio.prismic.io, instead of the CDN. We learned to be careful about publishing from scripts the hard way, with ten empty articles.

This post was published by one of those scripts, and it reached the site without a deploy.

Share
X LinkedIn Facebook WhatsApp Email
A hand placing a brass key on an empty wooden shelf

The key changes. The boxes do not.

Goes stale when
Anything is published
Cached for
5 seconds
Goes stale when
Never
Cached for
10 minutes, refreshed in the background
Goes stale when
Not applicable
Cached for
Not cached

From the fetch wrapper in our Prismic client, src/lib/prismic.ts.

An ID for one published state of your content. The API root returns the current master ref, every query includes it, and every publish creates a new one.

Not with this approach. Checking the ref every few seconds finds new content quickly, and queries keyed by ref never need clearing.

Something is holding an old ref: your own cache, a CDN, or a static build. Read the API root on the origin host to see whether the publish itself has landed.

We build and run modern framework sites end to end, from the CMS model to the server they deploy on.

See our framework work

More from the Journal

view all →