Next.js App Router에서 generateMetadata를 사용해
SEO 설정과 OpenGraph 이미지를 설정하던 중 예상치 못한 문제가 발생했다.
함수명, 변수명, 컴포넌트명은 모두 예시용 가명으로 작성되어 있다.
AWS Amplify로 배포한 Next.Js 앱에서 프로필 페이지를 포함한 여러 페이지에서 OpenGraph 이미지가 표시되지 않았다. 페이지 소스를 확인해보니 다음과 같은 메타 태그가 생성되어 있었다.
<meta property="og:image" content="http://localhost:3000/assets/profile_og.png">
이미 배포된 서비스임에도 불구하고 OpenGraph 이미지 URL이 localhost:3000을 가리키고 있었다.
[Next.js의 메타데이터 처리 방식]
OpenGraph, Twitter 메타 태그에 사용되는 이미지 URL은 절대 URL이어야 한다.
Next.js는 generateMetadata에서 이미지 URL이 상대 경로로 들어오면
이를 자동으로 절대 URL로 변환하려고 시도한다.
문제는 이 변환 과정에서 어떤 호스트를 기준으로 삼느냐다.
이 경우 Next.Js는 마지막 fallback 값인 localhost:3000을 사용한다.
결과적으로, 배포 환경임에도 OpenGraph 이미지가 localhost 기준으로 생성된 것이다.
[문제의 코드]
export async function generateMetadata({ params }: { params: { userId: string } }) {
const userData = await fetchUserData(params.userId);
const defaultImagePath = '/assets/default_profile.png';
const imageUrl = userData.profileImage || defaultImagePath; // 상대 경로
return {
openGraph: {
images: [
{
url: imageUrl, // 상대 경로 → localhost로 변환됨
alt: userData.name,
},
],
},
};
}
imageUrl이 상대 경로인 상태로 반환되면서 Next.js가 이를 자동 변환했고, 그 결과가 localhost:3000이었다.
가장 먼저 AWS Amplify 콘솔에서 환경변수 설정 상태를 확인했다.
[경로]
Amplify Console → App 선택 → Environment variables
여기서 사이트의 도메인이 각 브랜치에 정확히 설정되어 있는지 확인했다.
문제의 핵심은 Next.js의 자동 변환 로직에 의존했다는 점이었다.
따라서 상대 경로를 그대로 넘기지 않고, 메타데이터 단계에서 절대 URL을 명시적으로 생성하도록 수정했다.
export async function generateMetadata({ params }: { params: { userId: string } }) {
const userData = await fetchUserData(params.userId);
// 사이트 URL을 환경변수에서 가져오기
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';
const defaultImagePath = '/assets/default_profile.png';
// 기본 이미지를 절대 URL로 변환
const defaultImageUrl = `${siteUrl}${defaultImagePath}`;
// 프로필 이미지가 있으면 사용, 없으면 기본 이미지
const profileImageUrl = userData.profileImage
? formatImageUrl(userData.profileImage) // 이미 절대 URL로 변환하는 함수
: undefined;
const imageUrl = profileImageUrl || defaultImageUrl;
return {
openGraph: {
images: [
{
url: imageUrl, // 절대 URL 보장
alt: userData.name,
},
],
},
};
}
이후 배포 브랜치별로 NEXT_PUBLIC_SITE_URL을 명확히 분리했다.
[MAIN]
NEXT_PUBLIC_SITE_URL=https://example.com
[DEV]
NEXT_PUBLIC_SITE_URL=https://dev.example.com
빌드 타임에 url을 주입되도록 설정한 것이 핵심이다.
수정 후 생성된 메타 태그는 다음과 같이 나왔다.
<meta property="og:image" content="https://example.com/assets/profile_og.png">
배포 환경에서도 OpenGraph 미리보기가 정상적으로 표시되었다.
이 문제의 본질은 상대 경로 + 빌드 타임 메타데이터 + 환경변수 미설정의 조합이었다.
핵심 교훈은 명확하다.