Next.js Discord

Discord Forum

Can someone help me understand how server actions are cached?

Unanswered
Yellow and black potter wasp posted this in #help-forum
Open in Discord
Yellow and black potter waspOP
Server actions were unstable with Next.js 13 so I decided to continue to use the pages directory and now with the release of Next.js 14, it seems like the correct time to make the switch..

So I'm working through the official tutorial for Next.js 14 located here https://nextjs.org/learn which has been more or less pretty straightforward so far.

I am on chapter 12 and for context-related purposes, so far I have created and seeded a Vercel-hosted PostgreSQL DB, and then after that, I set up various server actions for receiving user and invoice data using SQL queries. These server actions are used by a few different components and after some thorough analysis using the network tab in the browser developers tools with some manual navigating: everything looks like it worked as it should.

Following this, the tutorial moves into mutating data, specifically user invoices by using server actions and I noticed that after using server actions to insert multiple invoices, the server components that I’m receiving from the server possess stale data!

At first, I thought that the server action responses for fetching the queries may have been cached so I implemented the noStore() function as recommended by the tutorial for my server actions. This should in theory force the server components to always run the server actions but the components were still loading steal data. I decided to do more investigating via the process of elimination and I next decided to stop and rerun my local project using “ctrl-c” -> “npm run dev”: the server components were still serving stale data. This is contrary to what next.js 14 + the tutorial advertises, so I decided to try deleting the generated “.next” folder and then restarting the local development, surely this would lead to some answers but no the data was still stale in the server components. This more or less told me that the issue had to be happening in the browser itself rather than next.js.
.

2 Replies

Yellow and black potter waspOP
Upon repeatedly invoking the server action to insert invoice rows into the SQL table, only by using the browser dev tool to “Empty cache and hard reload” could I get the server component to serve the dynamic data.

This has led to more questions than answers and tbh this framework release is too new to get my questions answered from ChatGPT. Next.js 13+ changed the way fetch() is used in server components and originally pushed using the experimental react use() hook (unstable at the time) for any other types of requests going out to enable caching. From my understanding, you can configure the caching properties in the updated fetch function per server action but this tutorial omitted using fetch entirely and jumped straight into using the import { sql } from "@vercel/postgres" to make calls from the server action functions. With Vercel's heavy focus on refactoring the fetch function post-Next.js 13 it doesn’t make much sense that in their official Next.js 14 walk-through tutorial (where server actions are supposed to finally be stable) they opted only to showcase running SQL queries from server actions instead.

I need to understand what is going on here because I cannot move forward with this framework until I do. I created and opted to use server actions in my serverside components but the components even when resent, my browser is loading from apparently its own cache the old serverside components rather than the new rehydrated ones.

Has anyone else dealt with this or have a good understanding of what is going on and if so would you be able to help me out? Thank you for anyone who is willing to take the time to answer.
Yellow and black potter waspOP
@Unknown User checking out the docs https://nextjs.org/docs/app/building-your-application/caching

Apparently, responses are also cached at the browser level as well as the server. From my understanding, the way server components are streamed to the client are different at the network level than the way client components have traditionally been sent and received. Much like how any arbitrary image from an img tag is transmitted and cached, server components are cached now at the browser level. With the fetch function, you can use the option { cache: 'no-store' } but this only caches the server action response. Next when you pass the data from the response to a server component, that server component is then cached at the browser level so even if you refresh the current session and still request new data with the server action fetch, rather then stream in and load the new variation of the server component you would instead load a stale cached js bundle from local memory for the server component. the docs say you can use export const dynamic = 'force-dynamic' to force any route segment to be dynamic in nature. but this will apparently force the server actions to be fired off every single time as well. The docs push to use the function revalidate() from within server actions to revalidate route segments but the patterns that need to be used are pretty confused and not defined well yet.