Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Setting Cookies Via Server Action Reloads Entire App #50163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task done
johnson-jesse opened this issue May 22, 2023 · 26 comments
Open
1 task done

Setting Cookies Via Server Action Reloads Entire App #50163

johnson-jesse opened this issue May 22, 2023 · 26 comments
Labels
Cookies Related to the async cookies() function. Server Actions Related to Server Actions.

Comments

@johnson-jesse
Copy link

johnson-jesse commented May 22, 2023

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.4.0: Mon Mar  6 20:59:28 PST 2023; root:xnu-8796.101.5~3/RELEASE_ARM64_T6000
    Binaries:
      Node: 16.14.0
      npm: 8.3.1
      Yarn: 1.22.19
      pnpm: 6.11.0
    Relevant packages:
      next: 13.4.4-canary.0
      eslint-config-next: 13.4.3
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.0.4

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true)

Link to the code that reproduces this issue or a replay of the bug

https://github.com/johnson-jesse/next-server-action-cookie

To Reproduce

  1. Clone repo, install, run dev.
  2. Click the first button labeled with "Via Server Action With Cookies"
  3. Notice the whole app re-renders.
  4. Optionally turn on "Highlight updates when components render." from developer window to see updates from button clicks.

Describe the Bug

Setting cookies in a server action causes the entire app to reload. This appears as a render glitch most noticeable when the layout is using a custom font that also needs to load.

Screen.Recording.2023-05-22.at.10.04.59.AM.mov

Expected Behavior

Setting cookies in a server action does not cause the entire app to reload thus avoiding loading the font again.

Which browser are you using? (if relevant)

Chrome Version 112.0.5615.137 (Official Build) (x86_64)

How are you deploying your application? (if relevant)

N/A

@johnson-jesse johnson-jesse added the bug Issue was opened via the bug report template. label May 22, 2023
@shuding
Copy link
Member

shuding commented May 22, 2023

This appears as a render glitch most noticeable when the layout is using a custom font that also needs to load.

That's dev only as we ditch all the cache of CSS resources when a server refresh is triggered, which should be fine. Are you seeing that on prod as well?

Also, if cookies are mutated inside an Action, it's expected to re-render the app because there could be data that depends on cookies.

@johnson-jesse
Copy link
Author

@shuding In prod, the glitch is only apparent when turning on highlighting. The prod example can be interacted with here.

Screen.Recording.2023-05-22.at.12.29.50.PM.mov

The visual glitch is gone here, but, do we really want to assume the entire app should reload every time "any" cookie is set or mutated? In some cases, a cookie should change frequently, with every click.

@J4v4Scr1pt

This comment has been minimized.

@GuillaumeHalb
Copy link

Same issue here.
Setting cookie triggers db queries, thus I would like to avoid those reloads.

@dance374
Copy link

Almost year has passed since you posted this and I'm experiencing same issue.

@coderbahrom

This comment has been minimized.

@a-bugaj
Copy link

a-bugaj commented May 21, 2024

I'm experiencing same issue.. will this be resolved somehow? setting a cookie using api route does not sound good.

@zoolyka
Copy link

zoolyka commented Jun 11, 2024

I'm facing the same issue.

The server action triggers all database queries (used to server side render the page of the actual route) when a cookie is set or deleted, even in production. This seems totally useless, since the components are not even rendered on the server and not sent to the client.

Looking for an explanation why this happens, and potentionally how to avoid it wihout switching to an API route.

@macdigger
Copy link

I wonder to which degree using api route could be considered a good practice.

I mean if it is - so it will be, but on the other hand, I'm using server actions (useFormState basically) to process user login form, which I process with server action, set a cookie if login was a success, and return json response.

However, due to full reload, the return value never actually has a chance to reach its caller, because the whole app gets remounted (not even refreshed, but complete remount, including reset of all vars defined by useState). It feels like a really thermonuclear thing to me?…

@jsabol
Copy link

jsabol commented Jun 29, 2024

I'm experiencing this issue when running getSession inside of a server action, in combination with useFormState. I tried this with essentially a NOOP just executing getSession, and I am experiencing a full page refresh with all fonts/css reloaded, causing the message not displaying due to the refresh. Next.js is recommending this paradigm (useFormState) instead of API requests. If I strip out the getSession call, the page does not refresh and the message displays.

import { getSession } from "@auth0/nextjs-auth0";

export async function saveUsername(
  prevState: SetUsernameFormState,
  formData: FormData
): Promise<SetUsernameFormState> {
  const session = await getSession();
  return {
    message: "Nothing to do",
  };
}

@comtef
Copy link

comtef commented Oct 4, 2024

I'm facing the same issue, using auth0 to check for authenticated user on server actions.
It triggers a full reload of the page. I'd like to find a solution to avoid refactoring all the app to api routes...

@magnusriga
Copy link

magnusriga commented Oct 6, 2024

Also, if cookies are mutated inside an Action, it's expected to re-render the app because there could be data that depends on cookies.

I tested this @shuding, and it seems that a Server Component "SC" does not actually re-render when a Server Action sets cookies after being called from a Client Component "CC" on the same route as the SC.

It seems it is necessary to call router.refresh() manually, in the CC, after the Server Action call.

Are others seeing that behavior as well?

EDIT:

From the docs it seems the Router Cache is indeed invalidated when cookies are changed in a Server Action, but a new request is not immediately sent to the server. The new request only happens upon navigation. To both invalidate the Router Cache, and send new request right away, use router.refresh().

@nbxNTC
Copy link

nbxNTC commented Oct 31, 2024

@magnusriga

Not sure if was a bug in the new version, but after upgrading to Next.js 15, updating the cookie in a Server Action called from a Client Component, is re-rendering the main Server Component.

  1. Server component (Do something and re-render after every cookie change)
  2. Client component (Call the server action)
  3. Server actions (Update cookie)

@JuSfrei

This comment has been minimized.

@underovsky
Copy link

Also run into this issue, this really messes the application flow as it's an unexpected behavior. I searched through Next.js docs and didn't find any mention of it.

Anyone found any workaround other than moving to API route?

@underovsky
Copy link

I found something semi-useful by analyzing headers.

It won't be helpful for cases when server action fetches data, but I personally found it useful to skip server component data validation for cookie-based data.

I noticed that upon the re-render of the server component via server action (that sets the cookie) Next.js is setting a new header called next-action. This header is not present upon the initial rendering.

Sample code:

import { cookies, headers } from "next/headers";

export default async function Page() {
  const isInitialRender = !headers().get("next-action");
  const cookie = cookies().get("some-cookie");
  
  // Sample validation triggered only on initial render
  if (isInitialRender && cookie && cookie.value !== "something-we-want") {
    throw new Error();
  }

  // Rest of the component
  // ...
}

@magnusriga
Copy link

magnusriga commented Nov 25, 2024

As noted in my edit above, it seems to work as it should. I.e. that the Router Cache is invalidated when cookies are set. As far as I can tell, there is no magic happening under the hood, other than that invalidation (which is a good thing).

Once the Router Cache has been invalidated, components that are cached, i.e. layout.tsx files, will be re-fetched from the server upon the next navigation. If you want to force the app to immediately re-fetch the layout.tsx files, then call router.refresh().

Unless I am missing something, it is as straight forward as that.

@mikebywaters
Copy link

Once the Router Cache has been invalidated, components that are cached, i.e. layout.tsx files, will be re-fetched from the server upon the next navigation.

@magnusriga Will these also be refetched if another server action is used, since there will be a POST to the current route that I assume interacts with the router in some way? If so, I imagine that would be unintended behaviour for most server action use-cases.

@vekinox
Copy link

vekinox commented Jan 1, 2025

Just chiming in to add another +1 to this, as I’ve encountered similar challenges.

In my case, setting an auth cookie in a server action during login causes the root layout to re-render, even though it has no dependencies on dynamic context like cookies or headers.

It would be beneficial if Next.js could scope the impact of server context changes more precisely so that:

  • Components or layouts that do not explicitly depend on dynamic context remain static and avoid unnecessary re-renders.
  • Contextual invalidations are limited to the subtrees directly affected by the change.

I understand that balancing dynamic rendering and cache invalidation is challenging, but I believe this optimization would align better with the principles of React Server Components.

@bttf
Copy link

bttf commented Jan 23, 2025

I'm experiencing this issue with a Sign In modal in my app. The modal contains an email/password form which calls a server action to sign in (using supabase). The signInWithEmail method that supabse provides will automatically set Set-Cookie in the response header.

However what's weird is that the clientside refresh does not happen when at the root URL of my app (/) - I'm able to sign in, and the client-side component is able to receive the return value from the server action and facilitate accordingly. There is no refresh, despite the present Set-Cookie header in the response.

The page refresh happens on another path (/invites/...), where the page refreshes as soon as the server action returns a response (containing the Set-Cookie header), and the client-side component is unable to process the return value. Both pages use the same modal, same action, etc.

@diegaccio
Copy link

Same issue here: I have a timed server action call that checks for new update in the db. The middleware updates the session cookie every time I hit a route. So the server action updates the cookie, causing a full refresh of the page that fetches all the data again from the db, even if there aren't any new updates in the db. This invalidates the purpose of my check. Am I doing something wrong?

@MohammadShehadeh
Copy link

MohammadShehadeh commented Feb 18, 2025

Same issue here.

This is one of the worst decisions that could be made. "You don't need to worry about revalidating the path we do it for you." This shows how much magic happens behind the scenes, making Next.js so frustrating to work with. There should be a way to opt out of this behavior

Using cookies.set or cookies.delete in a Server Action invalidates the Router Cache to prevent routes that use cookies from becoming stale (e.g. to reflect authentication changes).

https://nextjs.org/docs/app/building-your-application/caching#cookies

@Mnigos
Copy link

Mnigos commented Feb 20, 2025

Same issue here.

This is one of the worst decisions that could be made. "You don't need to worry about revalidating the path we do it for you." This shows how much magic happens behind the scenes, making Next.js so frustrating to work with. There should be a way to opt out of this behavior

Using cookies.set or cookies.delete in a Server Action invalidates the Router Cache to prevent routes that use cookies from becoming stale (e.g. to reflect authentication changes).

https://nextjs.org/docs/app/building-your-application/caching#cookies

I agree if I would like to revalidate the page after setting cookies I would just use revalidatePath right now I have to use route handler instead of server action because of that behavior.

@bdrtsky
Copy link

bdrtsky commented Feb 21, 2025

I've actually found this behavior useful. And seems like not only me. Are you sure it's a bug not a feature?

Image

@diegocrivelaro
Copy link

These are the moments when you need more autonomy, but Next.js restricts you. Is there any news regarding this?

@samcx samcx added Server Actions Related to Server Actions. Cookies Related to the async cookies() function. labels Mar 31, 2025
@david-scheiner-depop
Copy link

Have a variation of this. We set a few cookies in middleware. When we upgraded to v 14.2.25 we started having a problem where network traffic on some of our apis increased. We also had a different problem that would be too hard to explain here as it involves internal business logic but it relates to an id we set on the initial SSR of a particular page and that id getting updated during re-renders and different versions of it passing down to different requests. Both sets of issues were caused by these re-renders which happen from the middleware cookie updates. We changed the code to only set the cookie values when absolutely necessary. That fixed the business logic id problem but we still have increased api requests because we sometimes have to update cookie values.

What really surprised me is that we traced this to v14.2.8 of next. So the problem came in between 14.2.7 and 14.2.8. I call it a problem, Vercel apparently think it is a vital feature. But, for us, and seemingly for others on this thread, that feature is effectively a breaking change. Should it really have come in via a patch release?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Cookies Related to the async cookies() function. Server Actions Related to Server Actions.
Projects
None yet
Development

No branches or pull requests