Next.js Discord

Discord Forum

How to cache POST fetch call response & avoid re-calling the server on every page navigation

Unanswered
Lhasa Apso posted this in #help-forum
Open in Discord
Lhasa ApsoOP
Hey, I am trying to use pure Next.js fetch call to fetch data from GraphQL endpoint with pure Next.js caching.

Is it possible to cache the response from the fetch & avoiding recalling the function when revisiting the same page (or going on another with same fetch query).

Good start is to wrap it with React's cache function to avoid recalling it multiple times on the same page, but what about the navigation? I want to cache for certain amount of time, but per session meaning just for the client & when the page is refreshed all new data come in.

Goal is to avoid using 3rd party libraries like Tanstack Query & use pure fetch & Next.js.

Is this possible? Couldn't find any reference in docs. Thanks!

33 Replies

Lhasa ApsoOP
After some searching it looks like that client side caching for navigations is not something that Next.js solves & I should use Tanstack Query for this..? 🤷‍♂️
export default async function Page() {
  const data = await fetch('https://...', { next: { revalidate: 3600 } })
}
Or
export default async function Page() {
  const data = await fetch('https://...', { cache: 'force-cache' })
}
You can also get fancy and use cache components as well which has some good caching features that apply to components or functions
Tanstack is neat but you would lose all the befits of rcs but they do have tanstack for streaming but I my self would rather use cachcomponents and 'use cache'
Lhasa ApsoOP
@Patrick MacDonald thanks for the reply! I forgot to mention that the cache has to be per session, so in my scenario it is an admin panel which needs to have the data cached inside client cache which afaik 'use cache' & revalidate stands for global cache aka. partial prerendering. I was looking for some alternative like staleTime in Tanstack.
Use cash has different values for staleeness and can be defined
Lhasa ApsoOP
I managed to find [staleTimes](https://nextjs.org/docs/app/api-reference/config/next-config-js/staleTimes) which seems to be the thing I'm looking for.
With the cachLife(0
CacheLife
@Patrick MacDonald Use cash has different values for staleeness and can be defined
Lhasa ApsoOP
When I was playing with it I never managed to get the cache refreshed/fresh for example after the reload, etc.
@Patrick MacDonald With the cachLife(0
Lhasa ApsoOP
This I was testing with ^ cacheLife({ stale: 15 })
And there are pre set ones or fine grain control
And for things that are behind dynamic data, you can use cache remote
It all depends if you want to fetch your data on the client or the server
Lhasa ApsoOP
Priority is on the server to fully use the pontetional of the RSC.
Then cache components and use cache and use cache private and use cache remote are probably for you
the docs I shared explains how to control the cache life aka the stale time
usually I use the default profile and when i need the data revalidated I do it manually with updateTag or revalidateTag
Lhasa ApsoOP
Correct me if I am wrong, but the 'use cache' with cacheLife didn't seem to revalidate the date after given time.

The scenario I was testing:
- Have 2 pages /one & /two which both use 2 different fetch calls with cacheLife({ stale: 10 })
- I would expect after first fetch the response would be saved into the cache and for the stale time (10 seconds) I wouldn't be refetched on the server when navigating between /one & /two

Reality:
- it did not call directly the server after the build when navigated between pages, not even after the full reload, navigation, etc.
so on the dev server its usually fetched every time but if you log the data it will say cached
is the data not behind soemthign dynamic or auth? becuase if you 'use cache' but you display the date dont use suspense
Lhasa ApsoOP
the data are dynamic as I mentioned its admin dashboard which needs to have them relatively fresh, but avoid refetching them on every navigation
yes dynmic data that 'uses cache' doesnt need suspense while using cached components
export default async function Home(props: PageProps<'/'>) {
    const forkDataPromise = getForkData()
    const recentForksPromise = props.searchParams.then((search) =>
        getRecentForks({
            page: Number(
                Array.isArray(search.page)
                    ? search.page[0]
                    : (search.page ?? '1'),
            ),
        }),
    )

    return (
        <main className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden p-4 text-center">
            <div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_center,var(--tw-gradient-stops))] from-zinc-800/20 via-zinc-950 to-zinc-950" />

            <DaysSinceComponent forkDataPromise={forkDataPromise} />

            <div className="mt-16">
                <Suspense>
                    <RecentForks recentForksPromise={recentForksPromise} />
                </Suspense>
            </div>
        </main>
    )
}

export async function getForkData(): Promise<ForkData> {
    'use cache'
    cacheLife('hours')
    try {
        const response = await fetch(
            'https://api.github.com/repos/microsoft/vscode/forks?sort=newest&per_page=1',
            {
                headers: {
...
if you can fetch the data with out suspense you know its being cached and not refetched on nav
maybe try setting the state revalidate and expire, expire should work across builds
so stale is how often the client rechecks re validate is how often the server check in the background and expire is how often the max time b4 the server reintegrates the content