Next.js Discord

Discord Forum

Detecting whether cookies() is writable

Answered
Western paper wasp posted this in #help-forum
Open in Discord
Western paper waspOP
Is there any good way I can detect before calling cookies().set(...) whether I’m in an environment (eg server components) where it will fail, or I’m in an environment (eg route handlers / server actions) where it will succeed? I’m writing a function that uses cookies() and might be called from multiple contexts.
Answered by Western paper wasp
Another idea:
import { actionAsyncStorage } from 'next/dist/client/components/action-async-storage';

export function appCookiesWritable() {
  const asyncActionStore = actionAsyncStorage.getStore();
  return !!asyncActionStore && (asyncActionStore.isAction || asyncActionStore.isAppRoute);
}

This also relies on Next.js internals, but ones that seem more predictable than the name of a function. And this should break the TypeScript build if the internals change
View full answer

21 Replies

Western paper waspOP
One idea:
// Update cookies
let cookiesWritable = false;
try {
  cookies().delete(`test-${crypto.randomUUID()}`);
  cookiesWritable = true;
} catch {}

but this writes garbage to the Set-Cookie header of the response, which feels very unclean since that’s client-facing
Western paper waspOP
Another idea: cookies().set.name === 'callable' when it will error, and is anonymous when it won’t. This depends heavily on an implementation detail that could change at any time, though
Western paper waspOP
Another idea:
import { actionAsyncStorage } from 'next/dist/client/components/action-async-storage';

export function appCookiesWritable() {
  const asyncActionStore = actionAsyncStorage.getStore();
  return !!asyncActionStore && (asyncActionStore.isAction || asyncActionStore.isAppRoute);
}

This also relies on Next.js internals, but ones that seem more predictable than the name of a function. And this should break the TypeScript build if the internals change
Answer
@Western paper wasp if you want more explicit visual reference of if its writable, you could just make a
import "server-only";
export const serverCookies = () => cookies();
since writable is only via server components, and this import ensures it
that said, i know near is doing some great work in the efforts of adding visual hinting in webstorm for things like this
Western paper waspOP
@DirtyCajunRice | AppDir Cookies are not writable from server-components
Western paper waspOP
Additionally, I’m writing a function that can be used in either context (mutable cookies or immutable cookies), but can behave differently between the two.
@Western paper wasp <@184479429404262410> Cookies are *not* writable from server-components
Um… wut. httpOnly cookies are only writable from server components…
Western paper waspOP
No, the Next.js 13 cookies() API allows writing cookies from server actions and from route handlers, but not from React Server Components
or try it yourself @DirtyCajunRice | AppDir
@Western paper wasp No, the Next.js 13 `cookies()` API allows writing cookies from server actions and from route handlers, but not from React Server Components
Im sorry, that is correct. I wasnt making a distinction between a server component and a server action in this context as i assumed it was implied
Western paper waspOP
oh
well my question is specifically about finding a mechanism to make the distinction
@Western paper wasp well my question is specifically about finding a mechanism to make the distinction
Hmm…can you give me an example of where you would write to cookies in a server component?
in my head, it would require either an onClick, a useEffect, or a server action. the former requiring client, and the latter requiring SA. If its directly in the sc, it would screw up the render as adding a cookie makes a request causing an interruption in render that isnt gracefully handled
Western paper waspOP
I want to write a function that can be called in any server-side context, but conditionally only writes cookies when it’s not being called from a RSC
so I could call myFunction() from RSC, from route handlers, and from server actions, but it would skip setting cookies while in RSC
@Western paper wasp so I could call `myFunction()` from RSC, from route handlers, and from server actions, but it would skip setting cookies while in RSC
ahhh I see. you simply want to know what the magic thing is that goes inside of if to denote server. That, in and of itself, is a great question that i dont know the answer to but will try to find out