Next.js Discord

Discord Forum

Caching in Server Components

Answered
Sirex woodwasp posted this in #help-forum
Open in Discord
Sirex woodwaspOP
Hey guys.

I am having some serious issues regarding caching on server components. I've been trying to find a solid for for this for months, looked through a lot of posts and documentation, yet to no success.

The issue I am having, is that I want to re-fetch data when the user visits the page again after using <Link>
I am not wanting to use <a> because I do want the page and everything else to be cached, just not the fetching data.

Adding unstable_noStore() etc. does not work, as long as I am using <Link>, the page just loads the entire cached data.
I am currently using revalidatePath, but this seems like a weird workaround and need to implement this on every <Link> component. Any help would be really appreciated.
Answered by joulev
dev mode has some intentional caching changes, examples: everything is always dynamic and pages are built on-demand.

this has been the case since the pages router so i've never tested anything caching-related in dev mode haha.

but if dev mode doesn't do the router cache correctly, this is perhaps a bug of the staleTimes option, it is still experimental after all. i personally don't see why ignoring staleTimes makes sense for dev mode so this is unlikely to be intentional.

your app will be deployed in prod mode so the caching stuff it will work well, no worries.
View full answer

38 Replies

@joulev this is the [router cache](<https://nextjs.org/docs/app/building-your-application/caching#router-cache>). [i think it is a good feature](<https://joulev.dev/blogs/yes-nextjs-router-cache-is-actually-good>) but if you don't like it, you can configure [staleTimes](<https://nextjs.org/docs/app/api-reference/next-config-js/staleTimes>) for dynamic pages to be zero.
Sirex woodwaspOP
Setting staleTimes dynamic to 0 keeps the data cache. That's kind of the main issue I am having, of course I can use router.refresh() and all that, but it makes no sense to put it on every page that needs to fetch every time a user goes to the URL.
@Sirex woodwasp Setting staleTimes dynamic to 0 keeps the data cache. That's kind of the main issue I am having, of course I can use router.refresh() and all that, but it makes no sense to put it on every page that needs to fetch every time a user goes to the URL.
i will need a reproduction repository here. what you described in the original question shouldn't have anything to do with the data cache – unstable_noStore() should already opt out of the data cache.
@joulev i will need a reproduction repository here. what you described in the original question shouldn't have anything to do with the data cache – `unstable_noStore()` should already opt out of the data cache.
Sirex woodwaspOP
The repo I use is open source, I removed the staleTimes etc. because i figured it didn't help anyway. So far I just added a button "refresh" that calls router.refresh and an autoRefresh component that refreshes the router every 10 seconds.
https://github.com/docimin/cloudnet-webinterface/blob/RC-11/src/app/%5Blocale%5D/(dashboard)/dashboard/nodes/%5BnodeId%5D/page.tsx

This is an example page, where I fetch a node, show them on the client side where they can also edit them using server action. Everything goes great, just the part where I go from here: https://github.com/docimin/cloudnet-webinterface/blob/RC-11/src/app/%5Blocale%5D/(dashboard)/dashboard/nodes/page.tsx#L91-L96

to the first page said above
If you need actual instructions on how to use this, i can DM you login stuff.
@joulev how did you add staleTimes?
Sirex woodwaspOP
Like in the docs, copy pasted the experiments into njs config
also put static to 0 as well
@Sirex woodwasp also put static to 0 as well
it's dynamic. dynamic to 0.
static to 0, no wonder it doesnt do anything. your page is dynamic.
@joulev it's dynamic. dynamic to 0.
Sirex woodwaspOP
i said also
meaning both to 0.
As said, i copy pasted the experiments from the docs into my project, put both values to 0, didn't get any errors meaning the config was correct, didn't change anything.
then i don't know, sorry. the repo you sent is too big for me to debug anything – would appreciate a minimal reproduction repository (https://stackoverflow.com/help/minimal-reproducible-example) so i can have a full overview of the buggy behaviour.
every page has it
you can make any simple await fetch on an asynchronous page, go with <Link> to that page, go back with another <Link>, go to the same page where the fetch was and then you get the same result
because for some reason the entire page including the fetch (even with nostore and all that) gets cached, and <Link> doesn't care about any of the settings i used
i even tried revalidate 0, force dynamic and all that :/
i'll try to make a repro later
both pages contain a fetch to public data fetching the current datetime, however if you click on the <Link> button, you can see that once loaded, the values stay the same, even though the time should change.
literally nothing changed. all i did was: pnpm i, pnpm build and pnpm start
@joulev literally nothing changed. all i did was: `pnpm i`, `pnpm build` and `pnpm start`
Sirex woodwaspOP
I see! that explains a lot, that also works for me.
Could you try using pnpm dev instead?

Because I work in a dev environment almost always, since I "thought" this was the same as pnpm run build && start, just less performant etc. (Not done with most projects yet that require the fetching I am doing lately, hence never tried building and starting)

However for some reason in dev it does cache it!
@Sirex woodwasp I see! that explains a lot, that also works for me. Could you try using pnpm dev instead? Because I work in a dev environment almost always, since I "thought" this was the same as pnpm run build && start, just less performant etc. (Not done with most projects yet that require the fetching I am doing lately, hence never tried building and starting) However for some reason in dev it does cache it!
dev mode has some intentional caching changes, examples: everything is always dynamic and pages are built on-demand.

this has been the case since the pages router so i've never tested anything caching-related in dev mode haha.

but if dev mode doesn't do the router cache correctly, this is perhaps a bug of the staleTimes option, it is still experimental after all. i personally don't see why ignoring staleTimes makes sense for dev mode so this is unlikely to be intentional.

your app will be deployed in prod mode so the caching stuff it will work well, no worries.
Answer
(by the way, the router cache will be disabled (dynamic=0) by default starting next 15 so now perhaps it isn't necessary to report this bug anymore)
@joulev (by the way, the router cache will be disabled (dynamic=0) by default starting next 15 so now perhaps it isn't necessary to report this bug anymore)
Sirex woodwaspOP
Thanks for the help!

This certainly looks like a bug, yeah.

To the message I am replying to, isn't it technically still a bug? As it does work in prod but not in dev?
@Sirex woodwasp Thanks for the help! This certainly looks like a bug, yeah. To the message I am replying to, isn't it technically still a bug? As it does work in prod but not in dev?
next 14 is pretty much no longer under development. they are making next 15 (RC) right now and new versions of next 14 are only released as security fixes. the only reason next 15 is not stable yet is perhaps that react 19 is not stable yet.

so no point to report a (non-serious) bug in a version that is not actively worked on.

in next 15, the router cache is disabled for dynamic routes by default. so you don't have to explicitly set the staleTimes option. in the case you do need to set staleTimes, you would probably expect it to work in both dev and prod too, so the behaviour you are seeing is suddenly the intended behaviour. so yeah, it is no longer a bug in next 15.
Sirex woodwaspOP
Thanks for the help!
Sorry for all the confusion haha. Debugging is a mess.
Sirex woodwaspOP
in fact, doing a router.refresh is like 2-5x faster than setting staleTimes dynamic to 0
Sirex woodwaspOP
for almost each page, lol.
@Sirex woodwasp Sorry for the late question, but is it possible to also do staleTimes just for a part of the page? Instead of everything?
no it isn't possible unfortunately. it is global, you can't configure it for individual pages or parts of the page.

super slow
well, because the page is dynamic and it needs time to get the fresh data.

i discussed about this in the link i sent above, https://joulev.dev/blogs/yes-nextjs-router-cache-is-actually-good#case-1-data-updates-from-third-party--acceptably-stale-data, but basically in this case you probably want to use client-side data fetching instead of staleTimes.dynamic = 0.
if the data changes following a mutation done by the user, then you can use server-side data fetching: https://joulev.dev/blogs/yes-nextjs-router-cache-is-actually-good#case-2-data-updates-from-user--mutation-done-incorrectly