本文へ移動
verified onnext@16.3.5react@19
最終検証日 2026-09-26
Next.js道場

cookies の使い方。読める場所と書ける場所

Next.js の cookies() は await して使い、読むのはサーバー側ならどこでもできますが、書けるのは Server Action と Route Handler だけです。

読む・書く・消す

cookies() は next/headers から読み込み、await してから使います。

import { cookies } from 'next/headers'
 
export default async function Page() {
  const store = await cookies()
  const theme = store.get('theme')?.value ?? 'light'
  return <p>{theme}</p>
}

実機で、theme=dark; a=1 を送ると get('theme') の値は dark、has('theme') は true、getAll() の名前は theme と a でした。Cookie を送らなければ、get は undefined、has は false でした。

書けるのは Server Action と Route Handler だけ

Cookie を書くには、応答に Set-Cookie を載せる必要があります。そのため set と delete を呼べるのは、Server Action と Route Handler の中だけです。ページや layout の中で呼ぶと、開いたときにエラーになります(Cookies can only be modified の直し方)。

// app/actions.ts
'use server'
import { cookies } from 'next/headers'
 
export async function saveTheme(formData: FormData) {
  const store = await cookies()
  store.set('theme', String(formData.get('theme')))
}

実機で、このアクションをフォームから送ると、応答に Set-Cookie: theme=blue; Path=/ が付きました。同じ応答で描き直されたページは、もう新しい値(blue)を読んでいました。JavaScript が無いフォーム送信で確かめています。

何も指定しないと HttpOnly も Secure も付かない

書き方ごとに、応答の Set-Cookie を確かめました。

書き方と、応答に付いた Set-Cookie(実機で確かめた)
書き方Set-Cookie
set('theme', 'dark')theme=dark; Path=/
set('sid', 'abc', { httpOnly: true, secure: true, sameSite: 'lax', maxAge: 3600 })sid=abc; Path=/; Expires=…; Max-Age=3600; Secure; HttpOnly; SameSite=lax
delete('theme')theme=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT

何も指定しないと、付くのは Path=/ だけです。ログインの鍵のように、ブラウザの JavaScript から読まれたくないものには httpOnly: true を付けます。HttpOnly の付いた Cookie は、ページの JavaScript から読めません(MDN の Set-Cookie の説明)。secure: true を付けると、https でしか送られません。

maxAge を付けないと、有効期限の無い Cookie になり、ブラウザを閉じると消えます(MDN)。delete は、値を空にして有効期限を過去にすることで消しています。

読むとページは開かれるたびに描かれる

cookies() を読むページは、ビルドのときには描けません。Cookie は開いた人ごとに違うからです。実機のビルドの一覧でも、cookies() を読むページは ƒ(開かれたときに描く)、読まないページは ○(ビルドのときに描く)でした。

読むところだけを Suspense で囲めば、外側はビルドのときに描いておけます(Next.js のキャッシュ)。

proxy でも読み書きできる

ページを描く前に Cookie を見たいときは、proxy の req.cookies で読み、応答の cookies.set で書けます。

// proxy.ts
import { NextResponse, type NextRequest } from 'next/server'
 
export function proxy(req: NextRequest) {
  const res = NextResponse.next()
  if (!req.cookies.has('visited')) res.cookies.set('visited', '1', { maxAge: 60 })
  return res
}

実機で、ビルドのときに描いたページ(キャッシュから返るページ)の前でも、proxy は Cookie を読み、Set-Cookie を付けました。ページは描いたものがそのまま使われます。

Client Component では使えない

next/headers はサーバーの機能なので、use client のファイルでは読み込めません(next/headers を Client Component で使えない)。ページ(Server Component)で読み、必要な値だけを props で渡します。

まとめ

  1. await cookies() で読む。get・has・getAll はサーバー側ならどこでも使える
  2. set・delete は Server Action と Route Handler の中だけ
  3. 見られたくない値には httpOnly: true、https だけなら secure: true
  4. 読むページは開かれるたびに描かれる。ビルドのときに描きたい部分とは分ける

出典

このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。

理解できたか試す

では、このコードはどうなりますか。

ログインしたら Cookie に鍵を入れたいので、ページの中で set しました。ビルドは通りました。このページを開くとどうなりますか。

この問題を解くこのテーマの問題 4 問