결론:
쿠키를 다루고 싶은 경우, 프런트 서버에서 돌아가는 코드는 "next/headers"의 cookies 메소드를 사용하면 된다. 그러나 서버 컴포넌트에서 set cookies는 해줄 수는 없다. 클라이언트에서도 "next/headers"의 cookies 메소드를 사용할 수는 있지만 프런트 서버와 통신을 한다.
이유:
next가 제공하는 쿠키 메소드는 모두 서버 액션이다. get은 프런트 서버가 브라우저로부터 들어오는 요청의 헤더를 읽는 메소드, set은 프런트 서버가 브라우저로 보내는 요청에 쿠키를 set해주라고 명령하는 메소드다.
적용:
왠만하면 클라이언트에서 돌아가는 코드는 브라우저 저장소에 있는 쿠키 값을 활용하는 게 좋겠다. 예를 들어 document.cookie를 사용하면 된다.
브라우저가 가지고 있는 작은 데이터다.
이렇게 브라우저 store에 로컬 스코리지 처럼 있는 것을 확인 할 수 있다.
브라우저는 어떤 요청을 보낼 때 이 쿠키를 자동으로 요청 헤더에 넣어서 보낸다.

넥스트는 "next/headers"에서 쿠키와 관련된 메소드를 제공하고 있다.
https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options
"next/headers"는 서버 컴포넌트에서만 import 할 수 있다.
그러니까 관련 메소드들이 전부 프런트 서버에서 작동하는 서버 액션이라는 의미다.
그러나 이 액션을 클라이언트에서 사용하고 싶으면 어떻게 하면 좋을까?
라이브러리를 사용해도 좋고, 아래와 같이 util 함수로 빼서 클라이언트 컴포넌트에 import 해서 사용하면 된다고 한다.
"use server";
import { cookies } from "next/headers";
export async function setCookie(name: string, value: string) {
const oneDay = 24 * 60 * 60 * 1000; // Set expiry for one day
cookies().set(name, value, { expires: Date.now() + oneDay });
}
export async function deleteCookie(name: string) {
cookies().delete(name);
}
export async function getCookie(name: string) {
return cookies().get(name)?.value;
}
//test 페이지
"use client";
import React, { useEffect } from "react";
import { getCookie, setCookie } from "@/utils/next-cookie";
export default function TestPage() {
useEffect(() => {
async function testCookieAction() {
await setCookie("test", "cookie");
await getCookie("test");
}
testCookieAction();
}, []);
return <div>TestPage</div>;
}
이런 코드가 있다고 해보자.
그런 경우 브라우저 네트워크 창을 확이하면 아래와 같이 프런트 서버와 통신을 한 것을 확인할 수 있다.
가장 먼저 set cookie를 하기 위해 프런트 서버에 요청을 보냈다. 그리고 오는 리스폰스에 Set-Cookie가 있다. 이걸 받은 브러우저는 쿠키를 만들게 된다.
그 다음 get cookie를 하기 위해서 프런트 서버에 또 요청을 하는 것을 확인 할 수 있다. 응답으로 쿠키 값을 주고 있다.
즉, next/headers가 제공하고 있는 cookies 메소드들을 클라이언트에서 사용할 경우 프런트 서버와 통신이 일어난다는 점이다.
이를 클라이언트 코드에 남발할 경우 통신을 많이 하게 돼서 성능에 좋지 않을 수 있다.
The cookies function allows you to read the HTTP incoming request cookies from a Server Component or write outgoing request cookies in a Server Action or Route Handler.
넥스트 공식문서를 확인하면 위와 같이 설명하고 있다.
예를 들어 get은 프런트 서버가 프런트 서버에서 오는 요청의 헤더를 읽는 메소드, set은 프런트 서버가 브라우저로 보내는 요청에 쿠키를 set해주라고 명령하는 메소드다.
이걸 어떻게 활용할 수 있을까?
예를 들어 로그인이 되어 있다면 버튼 글자가 프로필, 아니면 로그인인 경우를 생각해 보자.
이 로그인 버튼을 서버 사이드 렌더링 하고 싶다면 어떻게 하는 게 좋을까?
로그인 유무에 대한 정보를 어디에 담으면 좋을까?
로컬 스토리지와 같은 곳은 프런트 서버가 접근하지 못한다.
그런데 쿠키에 저장하면 어떨까?
쿠키가 서버 측에 보내는 요청에 담겨서 가게 된다.
그러면 이때 next/headers를 읽고 사용하면 된다.
import { cookies } from "next/headers";
export default function ServerComponent() {
const cookieStore = cookies();
const loggedIn = !!cookieStore.get("accessToken");
return (
<button>
{loggedIn ? "프로필":"로그인"}
</button>
);
}
HTTP does not allow setting cookies after streaming starts, so you must use .set() in a Server Action or Route Handler.
주의해야 할 점이 하나 있다.
위에서 보면 스트리밍 중일 때는 쿠키를 set 할 수 없다는 얘기를 하고 있다.
import { cookies } from "next/headers";
export default function Test() {
cookies().set("test", "cookie");
return <div>Test</div>;
}
예를 들어 위와 같은 코드가 있다고 해보자.
의도는 이 이 컴포넌트가 돌아갈 때마다 쿠키를 set 해주는 거다.
그러나 위와 같은 코드를 돌려보면 에러가 뜬다.
이는 스트리밍과 연관이 있다.
스트리밍이란 서버에서 렌더링 한 걸 조금씩 넘겨주는 걸 말한다.
만일 스트리밍을 하지 않는다면 전부 렌더링한 뒤에 넘겨줘야 한다.'
그래서 내 생각에는 저렇게 서버 컴포넌트가 돌아가면 바로 스트리밍이 시작되는데 그 중간에 Set-Cookie를 헤더에 넣어주지 않는다는 말인 것 같다.
결론은 서버 컴포넌트에서는 구조적으로 setCookie를 해줄 수 없다.
쿠키를 다루고 싶은 경우, 프런트 서버에서 돌아가는 코드는 "next/headers"의 cookies 메소드를 사용하면 된다. 그러나 서버 컴포넌트에서 set cookies는 해줄 수는 없다. 클라이언트에서도 "next/headers"의 cookies 메소드를 사용할 수는 있지만 프런트 서버와 통신을 한다. 그래서 왠만하면 클라이언트에서 돌아가는 코드는 브라우저 저장소에 있는 쿠키 값을 활용하는 게 좋겠다. 예를 들어 document.cookie를 사용하면 된다.