앱이 Supabase 프로젝트와 이야기하게 만듭니다.
Next.js 프로젝트 루트에서 설치한다. @supabase/ssr가 쿠키 세션을 맡고, @supabase/supabase-js가 그 아래 API를 맡는다.
npm install @supabase/supabase-js @supabase/ssr
대시보드 Project Settings의 API에서 프로젝트 URL과 publishable 키를 복사한다. .env.local에 둔다. 이 파일은 Git에 올리지 않는다. 배포할 때는 같은 이름을 Vercel 환경 변수에 넣는다. HTML만 쓰는 앱은 그 파일 대신 브라우저 스크립트에 publishable 키를 둔다. 절차는 정적 사이트 · 데이터베이스에 있다.
NEXT_PUBLIC_SUPABASE_URL=https://프로젝트.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=publishable키
NEXT_PUBLIC_이 붙은 값은 브라우저 묶음에 들어간다. publishable 키는 그렇게 설계돼 있다. secret 키는 이 파일에도 NEXT_PUBLIC_ 없이, 그리고 클라이언트 코드에서 읽지 않는다.
'use client' 파일에서 쓴다. createBrowserClient는 여러 번 호출해도 인스턴스는 하나다.
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
)
}
파일 위치는 lib/supabase/client.js다. 경로 별칭 @/를 쓰면 import { createClient } from '@/lib/supabase/client'다.
서버 컴포넌트, 서버 함수, Route Handler는 요청마다 쿠키를 다시 읽어야 한다. 그래서 호출할 때마다 클라이언트를 만든다.
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {
// 서버 컴포넌트는 쿠키를 쓰지 못한다.
// 세션 갱신은 proxy.js가 맡는다.
}
},
},
}
)
}
로그인을 유지하려면 Next.js 16은 proxy.js, 15 이하는 middleware.js에서 세션을 갱신한다. 함수 이름만 다르고 안쪽 Supabase 코드는 같다. 전체 파일은 공식 문서의 Next.js 절을 복사한다. 여기서 줄을 빼면 사용자는 예고 없이 로그아웃된다.