【Next.js + Supabase】`cookies` was called outside a request scope.の解決方法

2024/07/23に公開

エラー状況

npm run buildでビルド時に下記のエラーが発生しました。
しかも、開発環境では発生せずに正常に動作していました。

Collecting page data  ..Error: `cookies` was called outside a request scope. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context

結論

エラー発生時はsupabaseクライアントを関数外で作成していました。

// 関数外でクライアント作成
const supabase = createClient()

export const fetchStudent = async () => {
    const { data } = await supabase.from('student').select()
    return data
}
export const fetchTeacher = async () => {
    const { data } = await supabase.from('teacher').select()
    return data
}

supabaseクライアントを関数内で作成することで解決できました。

export const fetchStudent = async () => {
    // 関数内に移動
    const supabase = createClient()
    const { data } = await supabase.from('student').select()
    return data
}
export const fetchTeacher = async () => {
    // 関数内に移動
    const supabase = createClient()
    const { data } = await supabase.from('teacher').select()
    return data
}

なぜエラーが発生したか?

エラーメッセージで案内された公式ドキュメントによると、動的APIをリクエスト外で呼び出すと発生するようです。
https://nextjs.org/docs/messages/next-dynamic-api-wrong-context

Cookieのようにリクエスト時にのみ分かる情報は動的APIに該当します。
@supabase/ssrのサーバー側のクライアント作成ではCookieを使用しているので、今回のエラーが発生していました。

import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { cookies } from 'next/headers'

export function createClient() {
  const cookieStore = cookies()

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll()
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options)
            )
          } catch {
            // The `setAll` method was called from a Server Component.
            // This can be ignored if you have middleware refreshing
            // user sessions.
          }
        },
      },
    }
  )
}

https://supabase.com/docs/guides/auth/server-side/nextjs?queryGroups=router&router=app

そもそも...

Supabaseの公式ドキュメントにサーバー側では毎回クライアントを作成するように説明がありました。
クライアント側ではシングルトンパターンになっていて、何回呼び出しても1つしか作成されないようです。

参考サイト

https://github.com/vercel/next.js/issues/67191
https://qiita.com/gozan/items/a3fd7c5d55b50b9cbb47

Discussion