본문으로 건너뛰기
개발 머꼬
개발 노트Next.js
hohyeon.dev16

Server Component에서 쿠키를 저장했는데 브라우저에 남지 않은 이유

  • #Common Pitfall
  • #Engineering Note
  • #Next.js

문제 발생

첫 방문자에게 테마 쿠키를 심으려고 페이지에서 바로 설정했습니다.

export default async function Page() {
  const cookieStore = await cookies();
  if (!cookieStore.has("theme")) {
    cookieStore.set("theme", "light"); // 여기서 오류
  }
  return <Dashboard />;
}

응답 헤더에 Set-Cookie가 없었고, 다음 요청에도 쿠키는 그대로 없었습니다.

원인 분석

HTTP 순서 때문입니다. Next.js 문서가 이유까지 적어둡니다 — HTTP는 스트리밍이 시작된 뒤에 쿠키를 설정하는 것을 허용하지 않으므로, .set은 Server Function이나 Route Handler에서 사용해야 합니다.

Server Component 렌더링은 이미 응답 본문을 만드는 단계입니다. 헤더는 그 전에 확정되어 나가므로 그 시점에 Set-Cookie를 덧붙일 자리가 없습니다.

문서는 개념도 함께 정리합니다 — 읽기는 브라우저가 요청 헤더로 보내준 데이터를 보는 것이라 Server Component에서 동작하고, 쓰기는 Server Component 렌더링 중에는 지원되지 않습니다. 쿠키를 수정하려면 클라이언트에서 Server Function을 호출하거나 Route Handler를 사용합니다. 서버는 Set-Cookie 헤더로 지시만 할 수 있고 실제 저장은 브라우저가 합니다.

.delete도 같은 제약입니다. 문서는 추가로 .set을 호출한 것과 같은 도메인, 같은 프로토콜에서 실행되어야 한다고 적습니다.

해결 방안

  1. 사용자의 행동으로 바뀌는 값은 Server Action에서 씁니다. 폼 제출이나 토글이 그 계기입니다.
"use server";
export async function setTheme(theme: string) {
  (await cookies()).set("theme", theme, { path: "/", httpOnly: false });
}
  1. 요청 단계에서 결정해야 하면 Route Handler나 proxy.ts로 옮깁니다. 첫 방문 식별자처럼 렌더 전에 정해져야 하는 값이 여기 해당합니다.

  2. 읽기만 하는 곳에서는 await를 잊지 않습니다. 문서 그대로 cookies는 프로미스를 반환하는 비동기 함수이며, Next 16에서는 동기 접근이 동작하지 않습니다.

  3. 쿠키를 읽으면 라우트가 동적이 된다는 것을 감안합니다. 문서 설명대로 cookies는 요청 시점 API라 레이아웃이나 페이지에서 사용하면 그 라우트가 동적 렌더링으로 전환됩니다. 전 페이지 공통 레이아웃에서 무심코 읽으면 사이트 전체가 동적이 됩니다.

  4. Server Action에서 쿠키를 바꾼 뒤 화면 데이터도 갱신해야 하면 revalidatePath/revalidateTag를 같은 함수 안에서 호출합니다. 문서가 안내하는 순서입니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.