RSC and CDN cache problems makes the next.js useless for the highload projects #59167
Replies: 11 comments 4 replies
-
Can someone explain to me why these RSC requests are used even when every single layout / page is a Client Component? layout.tsx : "use client"
export default function Layout({children}) => children page1/page.tsx : "use client"
import { Link } from "next/link"
export default function Page() => <Link href="/page2">page 2</Link> page2/page.tsx : "use client"
import { Link } from "next/link"
export default function Page() => <Link href="/page1">page 1</Link> |
Beta Was this translation helpful? Give feedback.
-
@studentIvan can you please describe how do you use cdn infront of the nextjs server? |
Beta Was this translation helpful? Give feedback.
-
Also, regarding Cloudflare:
This means a worker will run for all paths except But in my previous example, even when all pages are Client Components, and those .rsc files actually exist, they are still ignored, and a Deploying my previous example to Vercel doesn't seems very optimal either, because at If someone is on a tight budget, stick to the Pages router if you can. |
Beta Was this translation helpful? Give feedback.
-
Same problem, this is quite an issue for me for a high-traffic website. E.g.: // /?_rsc=gepvv
/products/1 → /
// /?_rsc=11gmh
/products/2 → / … although the RSC payload returned from the request is identical. This results in a huge number of different URLs that need to be saved in the CDN cache. Imagine a large e-commerce app that shows related products on a product detail page now having to cache all permutations of links between products instead of one page per product. Not sure if I'm missing something, but this seems to be quite a big issue for high-traffic sites that use dynamic segments with a lot of possible values. Cache size is one aspect here but the amount of requests that need to be handled by the origin server is another one. I'm probably missing a lot of details here, but I'm wondering if this could be solved at: … if the hash would only consider the currently active parent layout segments? E.g.: // ?_rsc=hash('products')
/products/1 → /
// … or a more complex example:
// ?_rsc=hash('en-us', 'products', 1, 'comments')
/en-us/products/1/comments/2 → /product/2 In these examples, the last part of the URL is not included in the RSC hash. Wouldn't that transport all relevant details, i.e. which layouts are already fetched, to efficiently fetch the minimum markup for the target page? Depending on the structure of an app, it might even be more efficient to simply fetch the whole markup for any given target page instead of granular cache entries that consider the current page if you have many pages below dynamic segments (e.g. Note that this wasn't an issue with the Pages Router as every page downloaded a cacheable JSON object that didn't depend on the previous route. FWIW, Remix doesn't seem to have this issue with their implementation of nested routes. They don't support RSC yet, but it seems like the problem is more related to nested routes than to RSC as far as I can tell. @huozhi any chance you could comment on this as you've worked on #50970? |
Beta Was this translation helpful? Give feedback.
-
are there really no solution except caching the requests on CDN? this was the initial reason I've move FROM pages router, to not have those mandatory "getServerSideProps" where they are identical. It seems very weird that as @josetr mentioned, a fully "use client"ed app would still make server requests. also, I believe these are related |
Beta Was this translation helpful? Give feedback.
-
Hi I'm trying to work out how I make the RSC requests work with a CDN when self hosting Nextjs. Is there any more info on this subject. I'm working on an ecommerce site with 100,000 products. Those products could appear in numerous product listing pages (search result pages). Each of those PLP pages are given unique URLs for SEO purposes. Take for example the following URLs:
They could all have the same products in. Due to the way the rsc hash is calculated that means I get a different
I have even gone to different areas of the site cart, checkout, order history, all with links back to the same product, they each produce different On a high throughput site I want to be able to cache identical data in the CDN close to the customer. At the moment that would be impossible as there would be to many variations on the rsc hash to make the caching effective. For solutions I think I only have 2 options:
In both cases there would be an extra cost to the client I'm trying to understand why the rsc has is different when it is always returning identical data? What is the purpose of this hash? As mentioned before could this just be set to
In this case the Next-Router-State-Tree and Next-Url will be set on where you are coming from and do not necessarily have an impact on the data need for the page we are going to. The Vary header will again have an impact on the CDN |
Beta Was this translation helpful? Give feedback.
-
This |
Beta Was this translation helpful? Give feedback.
-
Hey folks, I feel like you might want to open an actual bug ticket if you think the current behavior is not reasonable, with a minimal reproduction of the caching issue you experience. It's hard to reason based only on the messages sent here even for experienced Next.js dev I think. This feels quite advanced and might require changes in the way Next.js works so I am not sure you'll get the answers you want in a discussion. Unless this has already be moved from a discussion ? |
Beta Was this translation helpful? Give feedback.
-
Was facing this problem on my projects. RSC payload is used to load pages after initial load, so we don’t have to load the entire HTML document. My understanding is that client-side navigation (e.g. Next.js Link) doesn’t know whether the page is rendered on-demand. To support dynamic rendering, they made it a serverless function to ensure users are fetching the latest info from server, which also impacts the static pages. Hence, the RSC payload is not cached by browser, and is not served via CDN. This means if the user is not opening the static page directly (on initial load), opening a page is almost same as requesting a server rendered route. On Vercel, this caused a huge usage of serverless functions and data cache read (because it is cached by Vercel Data Cache), especially with prefetching enabled on the Next.js Link component. I cannot think of an optimal solution, the only idea is to use static export so at least it won't cause a huge usage of serverless functions. |
Beta Was this translation helpful? Give feedback.
-
RSC payload not being cached by the CDN nor by Next's caching system means interception routes (and parallel routes) are broken after deployments unless the whole cache is cleared. I implemented a modal with interception + parallel route, which breaks down into a full page load because the RSC payload hash has changed, and the old hash is no longer served by the new build. To keep the modal working, I have been clearing the (CDN) cache after each deployment, which hurts load time. |
Beta Was this translation helpful? Give feedback.
-
When using static export, what are the appropriate cache headers for these |
Beta Was this translation helpful? Give feedback.
-
Everytime user moves to the dynamic page and see the links, RSC makes different /xxx?_rsc=yyy requests with different _rsc hash. E.g. you have the e-commerce shop with the categories and the products.
Those _rsc requests have absolutely no cache, and CDN ignores them and pass them directly to the server, even we have the full page cached on the CDN for the specific product and the category.
And we even have to have the custom server, because we can't pass the headers with the cache-tag for the products to the CDN.
We can't have cache-tag working like this /myproduct, because we have a lot of countries and the normally the cache-tag should be like product-123456 (by id) so we can drop it by the product id but that is another problem.
(Next.js also slow on the cloudflare pages when we test, so aws look the only option at the moment.)
Problem example
from start page (see 71j4w)
Next-Router-State-Tree header:
["",{"children":[["lang","se","d"],{"children":["(defaultLayout)",{"children":["__PAGE__",{}]}]},null,null,true]}]
from another page (now is 4barx)
Next-Router-State-Tree header:
["",{"children":[["lang","se","d"],{"children":["(defaultLayout)",{"children":[["slug","dope","d"],{"children":["__PAGE__?{\\"gender\\":\\"Man\\"}",{}]}]}]},null,null,true]}]
Why do we need that?
Why can't we have the entire page passed by the
?_rsc=1
request with some configuration in the next.config file, to opt out the RSC cache system based on the router state but make it always return all the components?It must always be ?_rsc=1 with some configuration - so doesn't matter from what page I did open it and it would make possible to CACHE it on the CDN level, because the APP level is slow.
CDN level is close to the user and it makes the dynamic pages won't trigger the database requests again, also it makes possible to have server only for the static CDN generation.
What is actually difference for me between the 71j4w and 4barx? Why do I need to make the new request to the server?
To handle million requests with the 100k+ products we should really have a lot of servers count with the very expensive configuration. Vercel is much slower here and more expensive than aws or even aws wrappers like flightcontrol - so we have to think here about the servers.
I have not so many solutions right now to make it works
Faster solutions:
Crazy and complex solutions:
next.js/packages/next/src/client/components/router-reducer/fetch-server-response.ts
Line 102 in 87e0b44
Maybe somebody knows something...
Beta Was this translation helpful? Give feedback.
All reactions