Cache Control and Remix: Answering my own questions

Just a guy who loves to write code and watch anime.
Search for a command to run...

Just a guy who loves to write code and watch anime.
good
Qualities that make outstanding builders.

Bipedal vs quadrupedal: how many legs This is about the number of legs the creature walks on. Bipedal. Two legs. Humans, ostriches, T-rex, kangaroos, most fantasy humanoids. Quadrupedal. Four legs. Do

Intro You hear "lerp" and "smoothstep" everywhere in game dev. They sound like math jargon. They're not. Both are small tools that do the same job: smoothly move from one value to another. The problem

What is Kinematics Kinematics is the math field. It's the study of how things move without worrying about forces (which would be dynamics). FK and IK are the two branches: forward kinematics and inver

Intro Textures are usually the biggest cost in a 3D scene. Memory, bandwidth, and load time all get eaten by them. Resizing them is the obvious lever. There's more. This post is about the less obvious

I had some questions around Cache Control and using them in Remix.
This is kind of just me answering my own questions lol.
Before going over my questions, let's look at two examples and some of the values.
Cache-Control without stale-while-revalidate:
export let loader: LoaderFunction = async () => {
const posts = await db.post.findMany();
return json(posts, {
headers: {
"Cache-Control": "public, max-age=300, s-maxage=3600",
},
});
};
Cache-Control with stale-while-revalidate:
export let loader: LoaderFunction = async () => {
const products = await db.product.findMany();
return json(products, {
headers: {
"Cache-Control": "public, s-maxage=60, stale-while-revalidate=3600",
},
});
};
public: The response can be cached by the browser or any CDNs. It's made public.
max-age: The amount of seconds the response is considered fresh by the browser.
s-maxage: The amount of seconds the response is considered fresh by the CDN. This overrides max-age.
stale-while-revalidate: The amount of seconds the response is considered OK to serve stale (cached) data while the CDN revalidates the data.
No, it's not required. If you don't set it, the response will be private by default. This means the response can only be cached by the browser and no shared caches such as CDNs.
No, you don't need both.
If you only set max-age, it will be the same time for both browser and CDN caches.
If you only set s-maxage, this will only apply for shared caches like CDNs. The browser will use the default max-age value.
If you don't need different cache times for both browser and CDN, max-age is enough.
Let's go over two examples to understand when you may want max-age and s-maxage to be different.
Let's say you have a blog post that is frequently updated. By that, we can assume multiple times a day.
We can set max-age to 5 minutes and s-maxage to 1 hour. The browser will be ok with serving cached data for 5 minutes. After that, it will go to the CDN to check if the data is still fresh. We do this to avoid overloading the origin server.
The CDN is responsible for giving the browser the content. And every hour, it will check the origin server to get the latest data. This means the browser will have the latest data within 5 minutes after the CDN has checked the origin.
If you're serving personalized content to the user e.g. a personalized news feed page, you don't want this to be cached by the CDN since it shouldn't be shared.
So you can set max-age to 1 hour and s-maxage to 0. This means the browser will check the origin server every hour. And the CDN will not cache the response.
Yes, the purpose here is to make sure the browser has the latest data. We'll do some more aggressive caching for the CDN. CDNs can cache for longer and serve more traffic. Compared to browser cache, CDNs do not clear after session closes.
Quite a straightforward one: "Cache-Control": "public, s-maxage=60, stale-while-revalidate=3600".
We of course need to make the response public because we want the CDN to cache the response.
The CDN will cache it for 60 seconds. For 60 seconds, serving the stale (cached) data is fine. Then in the background, the CDN will get the latest data from the origin server. However, during that time, it is still allowed to serve stale data up to 3600 seconds which is 1 hour.
Honestly, in most cases, the background revalidation will happen faster than an hour. But it's good to have a buffer.
This is one of my favorite caching strategies. It's the default strategy for React Query, which I'm a big fan of because it provides a good experience. However, in the case of React Query, s-maxage is 0. Meaning, in most cases it will serve a very fresh response, but in some cases it will be stale due to background revalidation still happening.