개발 slecs

DB 기반 동적 SEO 메타데이터로 전환한 과정

목차

Next.js App Router의 generateMetadata 함수를 DB 기반으로 변경하는 작업을 진행했다. 정적 메타데이터에서 벗어나 동적으로 각 페이지마다 필요한 메타데이터를 데이터베이스에서 조회·생성하는 방식으로 전환한 것인데, 생각보다 영향 범위가 넓었다.

배경: 왜 DB 기반으로 옮겼나

초기에는 메타데이터를 하드코딩하거나 빌드 타임에 정적 파일로 생성했을 것 같다. 하지만 커머스 플랫폼 같은 서비스는 매일 상품이 추가되고, 가격이 변하고, 프로모션 정책이 바뀐다. 이런 변화를 매번 배포로 반영할 수는 없으니까 결국 DB에서 실시간으로 가져올 수밖에 없다.

특히 검색 엔진과 SNS 공유 시 나가는 OG(Open Graph) 메타태그는 실제 데이터와 동기화되어야 한다. 예를 들어, 상품 설명이나 이미지가 바뀌었는데 메타데이터가 옛날 것이면 SEO는 물론이고 사용자 경험도 헷갈린다.

각 파일의 역할과 변경의 의미

파일 역할 변경의 의미
next.config.ts Next.js 빌드 설정 동적 메타데이터 생성을 위한 환경 변수나 플러그인 추가 가능
src/app/layout.tsx App Router의 루트 레이아웃 generateMetadata 함수 구현체 수정, DB 조회 로직 적용
tsconfig.json TypeScript 컴파일 설정 seo_db.mjs 같은 모듈을 제대로 resolve하기 위한 paths 설정 조정

가장 핵심은 layout.tsx인데, 여기서 실제로 DB에 쿼리를 날린다. 다만 generateMetadata는 서버 컴포넌트에서만 호출 가능하고, 부족한 성능을 피하려면 캐싱을 잘 해야 한다.

모듈화 결정: seo_db.mjs를 왜 따로 뺐나

seo_db.mjs 같은 별도 모듈로 분리한 건 몇 가지 장점이 있다:

  • 테스트 용이성: DB 조회 로직을 단독으로 테스트할 수 있다.
  • 재사용: 여러 페이지나 API 엔드포인트에서 같은 DB 접근 로직을 쓸 수 있다.
  • 의존성 관리: layout.tsx가 비대해지지 않고, 데이터 접근 계층을 분리한다.
  • 마이그레이션 대비: 나중에 DB 라이브러리를 바꾸거나 캐싱 전략을 개선할 때 한 파일만 손보면 된다.

다만 팀원들이 이 구조를 이해하지 못하면 코드를 헤매게 된다. 그래서 코드리뷰 때 "여기서 왜 seo_db를 따로 뽑았는지", "이 함수는 언제 호출되고 캐싱은 어떻게 되는지" 설명하는 시간이 필요했다.

회고: 번역과 구현 사이에서

이 작업을 하면서 느낀 건, "DB-driven"이라는 한 줄 문구 안에 사실 여러 결정이 숨어 있다는 거였다:

  • Next.js 버전별로 generateMetadata 작동 방식이 다르다. 언제부터 비동기 함수를 지원하는지, 캐시 정책이 어떻게 되는지 공식 문서를 정확히 읽어야 했다.
  • tsconfig의 path alias나 module resolution이 잘못되면 seo_db를 import할 때 런타임에 에러가 난다. 특히 .mjs 확장자를 쓸 때는 더 조심해야 한다.
  • 프로덕션에서 "메타데이터 생성 느려지지 않을까"라는 질문이 나올 수 있다. DB 쿼리를 줄이거나 Redis 캐싱을 추가해야 할 수도 있다.

그래서 커밋 메시지는 짧지만, 구현 후 팀 문서에 "이 구조를 왜 선택했는가", "향후 확장 계획"까지 기록해야 한다고 생각했다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.