Next.js Discord

Discord Forum

React Server Components, the App Router, client-side navigation, and CDN caching

Unanswered
Spectacled bear posted this in #help-forum
Open in Discord
Spectacled bearOP
tl;dr: With the App Router, when a client-side navigation happens, the browser makes a request to the server for the new RSC payload of the destination route. But this request/response seems to be uncacheable at the CDN layer. Is this correct?

-----

I run a high-traffic, self-hosted ecommerce site with hundreds of thousands of pages. All Pages Router at the moment. Caching at the CDN is crucial for us - hitting the actual server is always a last resort at this scale. We cache both HTML documents and JSON API responses, so we can often skip the next.js server for both hard loads and client side navigations.

In short:
- When a customer comes to us from google, they can get the full page from the CDN, skipping the next.js server
- When a customer clicks a link from one product page to another product page:
- They already have all the javascript to render the product page
- So if we fetch the product data from the browser, we can skip the next.js server
- The product API is also CDN-cached for speed

We use getInitialProps so that a single data fetching function can run either on the server or the client depending on whether it's a hard or soft nav.

With the App Router, it seems that client-side navs will always trigger a request to the server for the RSC payload of the destination page. And crucially, this request contains a query param like _rsc=[some_hash], where the hash varies depending on where you are coming from. The response also seems to vary ever so slightly in a similar way - there is some sort of ID or hash in the response which seems to change.

I have found a couple of threads on github which discuss this but no definitive response:

- https://github.com/vercel/next.js/discussions/59167
- https://github.com/vercel/next.js/issues/65335

Am I right in thinking that the App Router is just incompatible with CDN caching during client side navs? It seems like there is no way to avoid hitting the origin server. What am I missing?

7 Replies

@Spectacled bear **tl;dr**: With the App Router, when a client-side navigation happens, the browser makes a request to the server for the new RSC payload of the destination route. But this request/response seems to be uncacheable at the CDN layer. Is this correct? ----- I run a high-traffic, self-hosted ecommerce site with hundreds of thousands of pages. All Pages Router at the moment. Caching at the CDN is crucial for us - hitting the actual server is always a last resort at this scale. We cache both HTML documents and JSON API responses, so we can often skip the next.js server for both hard loads and client side navigations. In short: - When a customer comes to us from google, they can get the full page from the CDN, skipping the next.js server - When a customer clicks a link from one product page to another product page: - They already have all the javascript to render the product page - So if we fetch the product data from the browser, we can skip the next.js server - The product API is *also* CDN-cached for speed We use `getInitialProps` so that a single data fetching function can run either on the server or the client depending on whether it's a hard or soft nav. With the App Router, it seems that client-side navs will always trigger a request to the server for the RSC payload of the destination page. And crucially, this request contains a query param like `_rsc=[some_hash]`, where the hash varies depending on where you are coming *from*. The response also seems to vary ever so slightly in a similar way - there is some sort of ID or hash in the response which seems to change. I have found a couple of threads on github which discuss this but no definitive response: - https://github.com/vercel/next.js/discussions/59167 - https://github.com/vercel/next.js/issues/65335 Am I right in thinking that the App Router is just incompatible with CDN caching during client side navs? It seems like there is no way to avoid hitting the origin server. What am I missing?
But this request/response seems to be uncacheable at the CDN layer. Is this correct?
yes and no. Yes, you can cache it, but no then your page won't load correctly on future other clients.

Nextjs loads only the data that is changed and replaces the dom. If you want to leverage other techniques like caching a whole route, you need to use the a tag instead of the <Link> tag
Spectacled bearOP
yes and no. Yes, you can cache it, but no then your page won't load correctly on future other clients.

So, "no", then? 🙂 If it won't work properly then it's uncacheable.

If I use an a then I'll be doing a hard reload and will lose state right? I want a soft nav which preserves client state, without having to hit the next.js server. It sounds like this isn't possible, so every single navigation on my site will have to hit the next.js server, and my CDN won't save me from this. Pretty huge limitation...
@Spectacled bear > yes and no. Yes, you can cache it, but no then your page won't load correctly on future other clients. So, "no", then? 🙂 If it won't work properly then it's uncacheable. If I use an `a` then I'll be doing a hard reload and will lose state right? I want a soft nav which preserves client state, without having to hit the next.js server. It sounds like this isn't possible, so every single navigation on my site will have to hit the next.js server, and my CDN won't save me from this. Pretty huge limitation...
If it won't work properly then it's uncacheable.
technically it is possible.
It's the same for server actions. Technically they are API endpoints, but you don't define an api route

I want a soft nav which preserves client state, without having to hit the next.js server.
That sounds more like you want a browser cache (persists client state and does not hit the server again when it was recently loaded)
@Spectacled bear solved?
Spectacled bearOP
No, not solved. I'm not talking about browser caching. I'm talking about CDN caching so that one customer can benefit from a different customer having already loaded a particular route. This is what I want:

1. Customer A hard-loads product X
2. Customer A clicks a link from product X to product Y
- The RSC payload for product Y is now cached in my CDN
3. Customer B hard-loads product Z
4. Customer B clicks a link from product Z to product Y
- The RSC payload for this client-side transition is served from my CDN, without hitting the next.js server

From what I can gather, this is not possible today, though it seems like it's being worked on: https://github.com/vercel/next.js/issues/65335#issuecomment-2583401824
@Spectacled bear solved?