도입: Next.js OG 이미지 설정이란
Next.js OG 이미지 설정은 웹 페이지를 카카오톡이나 페이스북, 트위터 같은 SNS에 공유할 때 표시되는 썸네일 이미지를 지정하는 작업이다. Open Graph 프로토콜에 따라 <meta property="og:image"> 태그를 HTML 헤드에 삽입하면 SNS 크롤러가 이를 읽어 미리보기 카드에 이미지를 표시한다. Next.js는 App Router에서 파일 기반 메타데이터와 동적 생성 함수를 제공해 이 과정을 단순화한다.
핵심 항목
정적 OG 이미지 파일 배치
정의
정적 OG 이미지 파일 배치는 app 디렉토리 내부의 라우트 폴더에 opengraph-image.jpg, opengraph-image.png, twitter-image.jpg 같은 특정 이름의 이미지 파일을 두는 방식이다. Next.js는 이 파일을 자동으로 인식해 해당 경로의 메타데이터에 OG 이미지 URL을 추가한다.
원리
Next.js는 빌드 시점에 라우트 폴더를 순회하며 예약된 파일명(opengraph-image, twitter-image)을 찾는다. 발견되면 해당 파일을 정적 자산으로 처리하고, 자동으로 생성된 메타데이터 객체에 <meta property="og:image" content="/경로/opengraph-image.jpg"> 형태로 삽입한다. 이 과정은 layout.tsx나 page.tsx에서 별도 코드를 작성하지 않아도 동작한다.
예시
프로젝트 구조가 app/blog/[slug]/page.tsx일 때, app/blog/[slug]/opengraph-image.png를 추가하면 해당 블로그 글 경로에서 자동으로 OG 이미지가 적용된다. 빌드 후 HTML 소스를 확인하면 <meta property="og:image" content="https://도메인/blog/포스트-슬러그/opengraph-image.png">가 삽입되어 있다.
오해
파일명을 og-image.png나 thumbnail.jpg처럼 임의로 지으면 자동 인식되지 않는다. Next.js 공식 문서에 명시된 opengraph-image, twitter-image 같은 정확한 이름만 지원한다. 확장자는 .jpg, .jpeg, .png, .gif를 사용할 수 있다.
generateMetadata 함수로 동적 URL 지정
정의
generateMetadata 함수는 페이지나 레이아웃에서 내보내는(export) 비동기 함수로, 메타데이터 객체를 반환해 헤드 태그를 동적으로 생성한다. openGraph.images 속성에 배열 형태로 이미지 URL을 지정하면 해당 경로가 OG 이미지로 사용된다.
원리
Next.js는 페이지를 렌더링하기 전에 generateMetadata를 실행해 반환된 객체를 HTML <head>에 반영한다. openGraph.images에 절대 URL이나 상대 경로를 넣으면 <meta property="og:image">로 변환된다. 동적 라우트에서는 params를 받아 데이터베이스 조회 결과나 외부 API 응답에서 이미지 URL을 가져올 수 있다.
예시
export async function generateMetadata({ params }) {
const post = await fetchPost(params.slug);
return {
openGraph: {
images: [{ url: post.coverImageUrl, width: 1200, height: 630 }],
},
};
}
이 코드는 블로그 포스트별로 다른 커버 이미지를 OG 이미지로 설정한다. 빌드 후 각 포스트 페이지의 HTML 헤드에는 해당 포스트의 coverImageUrl이 삽입된다.
오해
generateMetadata에서 반환한 이미지 URL이 상대 경로(/images/cover.jpg)일 경우, Next.js는 자동으로 도메인을 붙여 절대 URL로 변환한다. 하지만 SNS 크롤러가 접근할 수 없는 로컬 경로(file://)나 인증이 필요한 URL은 썸네일로 표시되지 않는다. 배포 환경에서 공개 접근 가능한 URL인지 확인해야 한다.
ImageResponse로 동적 이미지 생성
정의
ImageResponse는 Next.js가 제공하는 API로, JSX 문법으로 작성한 컴포넌트를 PNG 이미지로 변환해 반환한다. opengraph-image.tsx 또는 twitter-image.tsx 파일에서 기본 내보내기(default export)로 함수를 작성하면, 해당 라우트의 OG 이미지를 동적으로 생성할 수 있다.
원리
ImageResponse는 내부적으로 Vercel의 Satori 라이브러리를 사용해 JSX를 SVG로 변환한 뒤 PNG로 래스터화한다. 이 과정은 서버에서 실행되며, 생성된 이미지는 캐시되어 반복 요청 시 재사용된다. 텍스트, 배경색, 레이아웃을 코드로 제어할 수 있어 제목이나 작성자 정보가 포함된 맞춤형 썸네일을 자동 생성할 수 있다.
예시
// app/blog/[slug]/opengraph-image.tsx
import { ImageResponse } from 'next/og';
export default async function Image({ params }) {
const post = await fetchPost(params.slug);
return new ImageResponse(
(
<div style={{ display: 'flex', fontSize: 60, color: 'white', background: 'black', width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center' }}>
{post.title}
</div>
),
{ width: 1200, height: 630 }
);
}
이 코드는 블로그 포스트 제목을 중앙에 배치한 1200×630 이미지를 생성한다. 카카오톡에서 링크를 공유하면 제목이 포함된 썸네일이 자동으로 표시된다.
오해
ImageResponse는 모든 CSS 속성을 지원하지 않는다. Flexbox 레이아웃과 기본 텍스트 스타일은 작동하지만, position: absolute나 복잡한 애니메이션은 렌더링되지 않을 수 있다. 또한 외부 폰트를 사용하려면 fetch로 폰트 파일을 가져와 fonts 옵션에 전달해야 한다.
메타데이터 우선순위와 충돌 해결
정의
메타데이터 우선순위는 같은 속성을 여러 곳에서 정의했을 때 어느 값이 최종 HTML에 반영되는지를 결정하는 규칙이다. Next.js는 페이지 레벨 메타데이터가 레이아웃 레벨보다 우선하며, generateMetadata가 정적 metadata 객체보다 우선한다.
원리
Next.js는 라우트 트리를 따라 메타데이터를 병합한다. 루트 레이아웃(app/layout.tsx)에서 정의한 openGraph.images가 있고, 하위 페이지(app/blog/page.tsx)에서 다른 이미지를 지정하면 페이지 값이 최종 적용된다. 같은 파일 내에서는 generateMetadata 함수가 정적 export const metadata 객체를 덮어쓴다.
예시
루트 레이아웃에서 기본 OG 이미지를 설정하고, 특정 페이지에서만 다른 이미지를 사용하려면 해당 페이지의 generateMetadata에서 openGraph.images를 재정의하면 된다. 이때 루트 레이아웃의 다른 메타데이터(제목, 설명)는 유지되고 이미지만 교체된다.
오해
정적 파일(opengraph-image.jpg)과 generateMetadata를 같은 라우트에 동시에 두면 파일 기반 이미지가 우선된다. 동적 생성을 원한다면 정적 파일을 제거하거나, opengraph-image.tsx로 동적 생성 함수를 작성해야 한다. 두 방식을 혼용하면 의도와 다른 이미지가 표시될 수 있다.
핵심 원리 정리
Next.js OG 이미지 설정은 세 가지 방식으로 이루어진다. 첫째, 라우트 폴더에 opengraph-image.jpg 같은 예약된 이름의 파일을 배치하면 자동 인식된다. 둘째, generateMetadata 함수에서 openGraph.images 속성에 URL을 지정해 동적으로 이미지를 연결한다. 셋째, opengraph-image.tsx 파일에서 ImageResponse를 반환해 JSX 기반 이미지를 실시간 생성한다.
이 세 방식은 우선순위 규칙에 따라 병합된다. 파일 기반 이미지가 있으면 해당 라우트에서 자동 적용되고, 없으면 generateMetadata나 상위 레이아웃의 메타데이터가 사용된다. SNS 크롤러는 HTML <head>의 <meta property="og:image"> 태그를 읽어 썸네일을 가져오므로, 빌드 후 실제 HTML 소스를 확인하거나 카카오톡 개발자 도구의 "캐시 초기화" 기능으로 최신 메타데이터를 반영해야 한다.
흔한 오해
"이미지 파일 이름은 자유롭게 지어도 된다"
Next.js는 opengraph-image, twitter-image 같은 정확한 파일명만 인식한다. og-image.png나 thumbnail.jpg처럼 임의로 지으면 자동 설정이 작동하지 않는다.
"상대 경로 이미지는 절대 작동하지 않는다"
generateMetadata에서 /images/cover.jpg 같은 상대 경로를 반환하면 Next.js가 자동으로 도메인을 붙여 절대 URL로 변환한다. 다만 SNS 크롤러가 접근할 수 있도록 배포 환경에서 공개 경로여야 한다.
"ImageResponse는 모든 React 컴포넌트를 지원한다"
ImageResponse는 Flexbox 기반 레이아웃과 제한된 CSS 속성만 지원한다. 복잡한 컴포넌트나 외부 라이브러리를 사용하면 렌더링 오류가 발생할 수 있다.
"메타데이터를 수정하면 SNS에서 즉시 반영된다"
카카오톡과 페이스북은 URL별로 메타데이터를 캐시한다. 이미지를 변경한 후에는 카카오톡 개발자 도구나 페이스북 공유 디버거에서 캐시를 초기화해야 새 썸네일이 표시된다.
이해 확인 요약
Next.js에서 OG 이미지를 설정하려면 정적 파일 배치, generateMetadata 함수, ImageResponse 동적 생성 중 하나를 선택한다. 파일명은 opengraph-image로 정확히 지어야 자동 인식되며, 동적 라우트에서는 generateMetadata로 데이터베이스 값을 연결할 수 있다. ImageResponse는 JSX로 이미지를 생성하지만 제한된 CSS만 지원한다. 메타데이터 우선순위는 페이지가 레이아웃보다 높고, 파일 기반 이미지가 함수 기반보다 우선한다. 변경 후에는 SNS 크롤러 캐시를 초기화해 최신 썸네일을 확인한다.
