4.4
Metadata
지금부터는 Metadata의 개념과 Next.js에서 제공하는 Static Metadata와 Dynamic Metadata 기능에 대해서 살펴보도록 하겠습니다.
일반적으로 웹사이트에서 Metadata라고 하면 해당 웹사이트의 제목, 설명, 미리보기 이미지 등 웹사이트의 정체성을 나타내는 다양한 속성들을 의미합니다. 그리고 이러한 메타데이터는 아래 코드와 같이 HTML의 <head> 태그 내에 들어가게 됩니다.
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>소플 - soaple.io</title>
<meta name="description" content="소플">
<meta property="og:title" content="소플 - soaple.io">
<meta property="og:description" content="소플">
<meta property="og:url" content="https://www.soaple.io/">
<meta property="og:type" content="website">
<meta property="og:image" content="https://www.soaple.io/image/og_image.png">
<meta property="og:image:alt" content="Soaple cover image">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:site_name" content="Soaple">
<link rel="canonical" href="https://www.soaple.io/">
<link rel="manifest" href="/manifest.json">
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
<meta name="theme-color" content="#9DCC59">
</head>
<body>
...
</body>
</html>
웹사이트를 만들 때는 Metadata를 잘 작성하는 것이 중요합니다. 왜냐하면 아래와 같이 웹사이트의 링크가 공유되었을 때나, 검색 엔진의 검색 결과를 통해 노출되었을 때 사용자들이 Metadata를 통해서 어떤 웹사이트인지 파악할 수 있기 때문입니다.

우리가 직접 <head>태그 내에 메타데이터를 작성할 수도 있지만, Next.js에서는 조금 더 편리하게 Metadata를 정적으로 설정하거나 동적으로 설정할 수 있는 기능을 제공합니다. 지금부터는 각 기능에 대해서 하나씩 살펴보도록 하겠습니다.
Static Metadata는 말 그대로 정적인 메타데이터를 의미합니다. 즉, 동적으로 변하지 않는 메타데이터이기 때문에 고정된 값을 설정해놓으면 그 값이 계속해서 사용되는 것이죠.
Next.js에서 Static Metadata를 설정하려면, 아래 예시 코드와 같이 layout.tsx 또는 page.tsx 파일에서 metadata 객체를 export 하면 됩니다. 이 때 metadata의 타입은 next 패키지의 Metadata 타입으로 지정하면 됩니다. 굉장히 간단하죠?
// layout.tsx 또는 page.tsx 파일에서 정적 메타데이터를 설정하는 예시 코드
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: '소플의 홈페이지',
description: '안녕하세요, 소플의 홈페이지입니다.',
}
export default function Page() {
...
}
그리고 Next.js에서는 이렇게 export된 metadata 객체를 사용해서 해당 페이지의 메타데이터를 설정하게 됩니다.
Dynamic Metadata는 Static Metadata와는 다르게 동적으로 변하는 메타데이터를 의미합니다. 이러한 메타데이터는 현재 경로의 파라미터나 외부 데이터 또는 상위 메타데이터에 따라서 달라질 수 있습니다. 동적 메타데이터가 필요한 경우는 각 페이지마다 다른 메타데이터를 설정해야하는 경우입니다. 예를 들면, 블로그에서 각 게시글 페이지마다 다른 제목과 설명, 미리보기 이미지 등을 설정해야 하는 경우가 있습니다.
Next.js에서 Dynamic Metadata를 설정하기 위해서는, 아래 예시 코드와 같이 layout.tsx 또는 page.tsx 파일에서 metadata 객체를 반환하는 generateMetadata() 함수를 export 하면 됩니다. 이 때 generateMetadata() 함수가 반환하는 타입은 Promise<Metadata>로 지정하면 됩니다.
// layout.tsx 또는 page.tsx 파일에서 동적 메타데이터를 설정하는 예시 코드
import { Metadata, ResolvingMetadata } from 'next';
type Props = {
params: { id: string };
searchParams: { [key: string]: string | string[] | undefined };
};
export async function generateMetadata(
props: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
const { params, searchParams } = props;
// 경로 파라미터 추출
const { id } = await params;
// API 서버로부터 데이터 받아오기
const post = await fetch(`https://api.sample.com/post/${id}`).then((res) => res.json());
// (선택) 상위 메타데이터를 가져와서 확장
const previousImages = (await parent).openGraph?.images || [];
return {
title: post.title,
description: post.description,
openGraph: {
images: [post.coverImageUrl, ...previousImages],
},
};
}
export default function Page(props: Props) {
...
}
이렇게 하면 경로 파라미터의 값에 따라서 다른 메타데이터가 나타나게 됩니다. 위 예시에서는 경로 파라미터에 포함된 게시글의 아이디 값에 따라서, 해당 게시글의 제목과 설명, 커버 이미지가 메타데이터에 들어가게 됩니다.
NOTE. Metadata를 설정할 때 유의할 점
metadata객체와generateMetadata()함수는 서버 컴포넌트에서만 사용할 수 있습니다. 또한 같은 경로에 대해서metadata객체와generateMetadata()함수를 동시에export할 수 없고, 둘 중 하나만export해야 합니다. 즉, Static Metadata 또는 Dynamic Metadata 둘 중 하나만 사용해야 한다는 것입니다.
SEO는 Search Engine Optimization의 약자로 우리 말로는 검색엔진 최적화라고 합니다. 검색엔진 최적화라는 것은 우리가 만든 웹사이트가 검색엔진에서 더 높은 순위에 나올 수 있도록 최적화하는 과정이라고 보면 됩니다. SEO가 중요한 이유는 검색 결과에서 웹사이트가 보다 더 높은 순위에 나오게 함으로써 더 많은 사람들에게 노출될 수 있고, 그로 인해 별다른 광고비용 없이도 방문자 수나 회원 수를 자연스럽게 늘릴 수 있기 때문입니다. 그래서 SEO는 내가 만든 서비스나 웹사이트를 키우는데 가장 중요하고 효과적인 방법 중 하나입니다.
이러한 검색엔진 최적화를 위해서는 다양한 부분의 노력이 필요합니다. 그 중에 제일 기본적이며 손쉽게 할 수 있는 것이 바로 검색 엔진에 메타데이터를 잘 제공하는 것입니다. Next.js에서는 앞에서 배운 것처럼 Static 또는 Dynamic Metadata를 사용해서 각 페이지의 메타데이터를 설정할 수 있습니다. 그리고 이러한 메타데이터를 통해 검색엔진에서 특정 키워드로 검색했을 때 더 상위에 노출되는 것을 기대해볼 수 있습니다.
robots.txt 설정하기robots.txt 파일은 웹사이트의 루트 경로에 위치한 텍스트 파일로, 웹 크롤러(로봇)들이 해당 사이트의 어떤 부분을 크롤링해도 되는지 또는 크롤링하지 말아야 하는지를 명시하는 규칙을 포함하고 있는 파일입니다. 웹사이트 소유자는 robots.txt 파일을 통해 검색 엔진 및 기타 크롤러의 접근을 제어할 수 있습니다.
Next.js의 App Router에서 robots.txt 파일을 설정하기 위해서는, 아래와 같이 app 디렉토리의 최상위 경로에 robots.txt 파일을 추가하면 됩니다.
app/robots.txt 파일 예시
User-Agent: *
Allow: /
Disallow: /private/
Sitemap: https://www.soaple.io/sitemap.xml
만약 robots.txt 파일을 동적으로 생성하고 싶다면, app 디렉토리의 최상위 경로에 robots.ts 파일을 생성하고 아래 코드와 같이 robots() 함수를 default export 하면 됩니다.
// app/robots.ts
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
allow: '/',
disallow: '/private/',
},
sitemap: 'https://www.soaple.io/sitemap.xml',
};
}
이렇게 함으로써 검색 엔진 크롤러에게 사이트의 어떤 부분에 액세스할 수 있는지를 알려줄 수 있습니다.
Sitemap은 단어의 의미처럼 웹사이트의 구조를 한 눈에 파악할 수 있는 지도를 나타냅니다. 웹사이트에 어떤 페이지들이 존재하는지, 마지막으로 변경된 시점은 언제인지 등의 정보를 담고 있습니다. Sitemap은 XML 형식으로 작성하며 웹사이트의 구조와 콘텐츠에 대한 정보를 포함합니다. SEO 관점에서 Sitemap이 중요한 이유는 검색 엔진이 웹사이트를 더 효율적으로 크롤링하고 색인화할 수 있도록 도와주기 때문입니다.
Next.js의 App Router에서 Sitemap을 설정하기 위해서는, 아래와 같이 app 디렉토리의 최상위 경로에 sitemap.xml 파일을 추가하면 됩니다.
app/sitemap.xml 파일 예시
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://www.example.com/</loc>
<lastmod>2024-07-30T16:02:34.074Z</lastmod>
<changefreq>monthly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>http://www.example.com/about</loc>
<lastmod>2024-01-28T12:01:74.056Z</lastmod>
<changefreq>yearly</changefreq>
<priority>0.8</priority>
</url>
</urlset>
만약 /app/sitemap.xml 파일을 동적으로 생성하고 싶다면, app 디렉토리의 최상위 경로에 sitemap.ts 파일을 생성하고 아래 코드와 같이 sitemap() 함수를 작성하여 default export 하면 됩니다. 여기서 sitemap() 함수는 Sitemap에 들어갈 웹사이트의 각 경로와 세부 정보를 담은 객체들을 배열 형태로 리턴하면 됩니다.
import { MetadataRoute } from 'next';
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: 'https://www.example.com',
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 1,
},
{
url: 'https://www.example.com/about',
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 0.8,
},
];
}
마지막 업데이트: 2025년 10월 24일 02시 09분
이 문서의 저작권은 이인제(소플)에 있습니다. 무단 전재와 무단 복제를 금합니다.