본문 바로가기

개발 공부/React

Clerk 인증 정보와 Prisma User 테이블 동기화(sync)

출처 : https://github.com/Yundimin/social-app

 

GitHub - Yundimin/social-app: social-app

social-app. Contribute to Yundimin/social-app development by creating an account on GitHub.

github.com

 

파일 경로  변경 내용
src/actions/user.actions.ts Clerk 사용자 정보를 Prisma User DB에 동기화하는 syncUser 함수 추가
src/lib/prisma.ts PrismaClient를 싱글턴으로 관리하는 유틸 추가
src/components/Navbar.tsx Navbar 렌더링 시 DB 동기화 로직 연동 및 UI 텍스트 변경 (My Social → Social App)

 

 

 

src/lib/prisma.ts – PrismaClient 싱글턴 패턴

import { PrismaClient } from "@generated/prisma/client";

const prismaClientSingleton = () => new PrismaClient();
 // 바로 인스턴스를 만들지 않고 함수로 감싸 두면, 지연 생성(lazy creation) 과 타입 재사용(ReturnType)에도 좋습니다.

declare const globalThis: {
  prismaGlobal: ReturnType<typeof prismaClientSingleton>;
} & typeof global;

const prisma = globalThis.prismaGlobal ?? prismaClientSingleton();

if (process.env.NODE_ENV === "production") globalThis.prismaGlobal = prisma;

export default prisma;

 

  • PrismaClient 인스턴스가 중복 생성되는 문제를 방지하기 위한 전형적인 싱글턴 패턴(Singleton Pattern) 코드입니다.
  • 개발 환경(NODE_ENV !== production)에서는 Next.js의 Hot Reload로 인해 PrismaClient가 여러 번 생성될 수 있습니다.
    → globalThis.prismaGlobal에 저장하여 이를 방지합니다.
  • 프로덕션 환경에서는 단일 인스턴스만 유지하도록 조건문 처리되어 있습니다.

싱글턴(Singleton)

 

  • 정의: 어떤 클래스의 인스턴스를 애플리케이션 전체에서 딱 1개만 만들고 계속 재사용하는 패턴.
  • 왜 필요한가(Prisma에서)
    • 개발 모드에서 파일이 저장될 때마다 모듈이 다시 로드(HMR) → new PrismaClient() 가 누적 생성 → DB 커넥션 과다로 오류(Prisma has already been started, Too many connections, 등)가 납니다.
    • 한 번 만든 PrismaClient를 전역에 보관해 두고, 다음번에는 새로 만들지 말고 그 전역 인스턴스를 쓰자는 게 핵심.

 

 


 

 

 

src/actions/user.actions.ts – Clerk 사용자 동기화

"use server";

import prisma from "@/lib/prisma";
import { auth, currentUser } from "@clerk/nextjs/server";

export async function syncUser() {
  try {
    const { userId } = await auth();
    const user = await currentUser();

    if (!userId || !user) return null;

    const existingUser = await prisma.user.findUnique({
      where: { clerkId: userId },
    });

    if (existingUser) return existingUser;

    const dbUser = await prisma.user.create({
      data: {
        clerkId: userId,
        name: `${user.firstName || ""} ${user.lastName || ""}`,
        username: user.username ?? user.emailAddresses[0].emailAddress.split("@")[0],
        email: user.emailAddresses[0].emailAddress,
        image: user.imageUrl,
      },
    });

    return dbUser;
  } catch (error) {
    console.log("Error in syncUser", error);
  }
}
  • 서버 액션("use server") 으로 선언되어 서버에서 직접 실행됩니다.
  • Clerk의 auth()와 currentUser()를 통해 로그인 정보를 가져옵니다.
    • auth()는 빠르고 간단한 인증 체크용,
    • currentUser()는 DB에 넣을 상세 정보용입니다.
  • DB에 이미 존재하면 그대로 반환, 없으면 새로 생성(create).
    • Prisma의 findUnique()는 고유 필드(Primary Key나 unique field) 로 하나만 검색할 때 사용합니다.
  • Clerk에서 가져온 정보를 기반으로 DB 필드를 채워 넣음:
    • clerkId, name, username, email, image
  • 로그인 시 자동으로 DB에 유저를 생성하고 중복 방지하는 함수입니다.

 

 


src/components/Navbar.tsx – 사용자 동기화 연결

import { currentUser } from "@clerk/nextjs/server";
import { syncUser } from "@/actions/user.actions";

export async function Navbar() {
  const user = await currentUser();
  if (!user) await syncUser(); // POST: DB 동기화

  return (
    <nav className="sticky top-0 w-full border-b bg-background/95 backdrop-blur">
      <Link href="/" className="text-xl font-bold text-primary font-mono tracking-wider">
        Social App
      </Link>
    </nav>
  );
}

 

  • 로그인된 Clerk 사용자가 없을 경우 syncUser()를 호출해 DB 동기화 시도.
  • sync function Navbar()로 서버 컴포넌트로 선언되어 있음.

 

'개발 공부 > React' 카테고리의 다른 글

Next.js App Router 자동 실행 규칙  (0) 2025.11.24
Next.js Route Handler  (0) 2025.11.22
useSearchParams hook 만들기  (1) 2025.10.22
custom modal 만들기  (0) 2025.10.21
React App Router, Page Route  (0) 2025.10.19