Rae.

Next.js로 블로그 SEO 적용하기

2025-05-14

개요

Next.js로 만든 블로그에 검색엔진 최적화(SEO)를 적용하는 방법을 설명합니다.

SEO란 무엇인가

SEO는 Search Engine Optimization의 약자로, 검색엔진 최적화를 의미합니다.

검색엔진이 웹사이트의 콘텐츠를 더 잘 이해하게 하고, 사람들이 해당 사이트를 쉽게 찾고 방문할 수 있도록 돕는 방법론입니다.

그래서 SEO를 잘 적용하면, 사용자가 검색할 때 웹사이트가 검색 결과 상단에 뜰 가능성이 높아집니다.

그렇다면 검색 엔진은 어떻게 동작하기에 왜 SEO를 잘 설정해야 할까요?

검색엔진의 동작과정

Google 검색엔진을 기준으로 설명합니다.

Google과 같은 검색엔진은 Googlebot이라는 크롤러를 사용하여 끊임없이 웹을 탐색하고 색인에 추가할 페이지를 찾습니다.

검색엔진은 다음 3단계로 동작합니다.

  1. 크롤링: 크롤러라는 자동화된 프로그램을 사용하여 인터넷에서 찾은 페이지로부터 텍스트, 이미지, 동영상을 다운로드 합니다.
  2. 색인 생성: 페이지의 텍스트, 이미지, 동영상 파일을 분석하고 대규모 데이터베이스인 Google 색인에 이 정보를 저장합니다.
  3. 검색결과 게재: 사용자가 검색하면 사용자의 검색어와 관련된 정보를 반환합니다.

위 과정 중 크롤링과 색인 생성에 대해 더 자세히 알아보겠습니다.

크롤링

크롤링은 크롤러가 새로운 페이지나 업데이트된 페이지를 찾아 검색엔진에 추가하는 과정입니다.

크롤러가 페이지의 URL을 발견하면, 해당 URL에 접속하여 내용을 확인하기 위해 페이지를 방문합니다. 이 과정을 "URL 검색"이라고 합니다.

하지만 크롤러가 발견한 모든 페이지를 크롤링하는 것은 아닙니다. 사이트 소유자가 크롤링을 허용하지 않은 경우, 또는 사이트에 로그인해야만 접근 가능한 경우, 해당 페이지는 크롤링되지 않습니다. 이때 크롤링 허용 여부를 제어하는 대표적인 수단이 바로 **robots.txt**입니다.

robots.txt는 크롤링해서는 안되는 사이트 내 URL 또는 디렉토리를 검색엔진에게 알려주는 텍스트 파일입니다. 예를 들어, 관리자 페이지나 개인정보 페이지처럼 검색 노출이 불필요하거나 원치 않는 경로를 제외할 때 사용됩니다.

반대로, 사이트 소유자가 Googlebot이 우선적으로 크롤링해야 할 URL 목록을 명시적으로 제출하고 싶을 때는 **sitemap.xml**을 사용합니다. sitemap.xml은 웹사이트 내 주요 페이지들의 URL과 업데이트 주기, 우선순위 등을 담고 있는 XML 형식의 파일입니다. 검색엔진이 사이트 구조를 보다 쉽게 이해하고 효율적으로 크롤링할 수 있도록 도와줍니다.

즉, robots.txt크롤링을 제한하거나 허용 범위를 정의하는 역할을 하고, sitemap.xml검색엔진이 크롤링을 더 잘 하도록 안내하는 역할을 수행합니다.

색인 생성

크롤링이 완료되면, 검색엔진은 수집한 페이지의 내용을 분석하여 검색 색인에 저장하는 색인 생성(Indexing) 단계를 수행합니다.

이 단계에서는 페이지 내의 텍스트 콘텐츠, 이미지, 동영상뿐 아니라 <title>, <img>alt 속성, <head>안에 작성된 <meta>와 같은 메타데이터(metadata) 정보까지 함께 분석됩니다. 이러한 정보를 바탕으로 페이지의 주제, 구조, 품질을 이해하고, 사용자의 검색어에 적절히 대응할 수 있도록 색인에 등록합니다.

Next.js로 SEO 최적화하기

앞에서 언급한 SEO 최적화를 위해 필요한 metadata, robots.txt, sitemap.xml을 Next.js 에서는 Metadata API 를 통해 쉽게 적용할 수 있습니다.

Metadata 적용하기

Next.js에서는 Metadata 객체를 통해 <head> 태그 안에 들어가는 <meta> 태그의 titledescription 속성 등을 정의하여 자동으로 적용해줍니다.

정적 파일인 layout.tsx이나 page.tsx 에 작성할 경우, 모든 페이지에 공통적으로 정의하고 싶은 메타데이터 또는 페이지 고유의 정보를 정의하는 메타데이터를 적용할 수 있습니다.

export const metadata: Metadata = {
  title: {
    default: "Rae",
    template: "Rae - %s",
  },
  description:
    "학습한 내용에 대해 다른 사람도 쉽게 읽을 수 있도록 공유하는 김승래의 개인 기술 블로그",
  icons: {
    icon: "/favicon.ico",
  },
  robots: "index, follow",
};

정적 라우트 page.tsx 파일에 고유한 메타데이터를 적용할 수도 있습니다.

동적 라우트인 app/post/[slug]/page.tsx에서는 generateMetaData() API를 통해 페이지마다 다른 title 데이터를 메타데이터로 적용해줄 수 있습니다.

이전에 Next.js + MDX로 포스팅 기능 구현하기 에서 작성했던, slug 인자를 통해 slug에 해당하는 MDX 게시글의 데이터를 반환하는 parsePostDataBySlug() 함수를 이용해 generateMetadataAPI가 받아오는 slug로 동적인 메타데이터를 적용할 수 있도록 했습니다.

import { parsePostDataBySlug } from "@/lib/mdx";
import { Metadata } from "next";

export async function generateMetadata({
  params,
}: {
  params: Promise<{ slug: string }>;
}): Promise<Metadata> {
  const { slug } = await params;
  const { postMetaData } = parsePostDataBySlug(slug);

  return {
    title: postMetaData.title,
    description: postMetaData.description,
    openGraph: {
      title: postMetaData.title,
      description: postMetaData.description,
    },
  };
}

sitemap & robots 적용하기

Next.js 프로젝트에서 sitemap.xmlrobots.txt를 관리하기 위해서는 public 폴더에 정적 파일로 생성해줘야 합니다.

하지만 블로그의 게시글을 작성해 페이지가 추가될 때마다, sitemap.xml에 해당 게시글의 url을 직접 갱신해줘야하는 불편함이 존재합니다.

Next.js에서는 sitemap.tsrbots.ts라는 특별한 라우트 핸들러 파일을 사용해 sitemap.xmlrobots.txt을 편하게 괸리할 수 있습니다.

예를 들어, sitemap.tsapp 폴더에 아래와 같이 생성했을 경우

import type { MetadataRoute } from "next";

export default function sitemap(): MetadataRoute.Sitemap {
  return [
    {
      url: "https://acme.com",
      lastModified: new Date(),
      changeFrequency: "yearly",
      priority: 1,
    },
    {
      url: "https://acme.com/about",
      lastModified: new Date(),
      changeFrequency: "monthly",
      priority: 0.8,
    },
    {
      url: "https://acme.com/blog",
      lastModified: new Date(),
      changeFrequency: "weekly",
      priority: 0.5,
    },
  ];
}

Next.js에서는 빌드 시, 해당 파일을 다음과 같이 변환해줍니다.

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://acme.com</loc>
    <lastmod>2023-04-06T15:02:24.021Z</lastmod>
    <changefreq>yearly</changefreq>
    <priority>1</priority>
  </url>
  <url>
    <loc>https://acme.com/about</loc>
    <lastmod>2023-04-06T15:02:24.021Z</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
  </url>
  <url>
    <loc>https://acme.com/blog</loc>
    <lastmod>2023-04-06T15:02:24.021Z</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.5</priority>
  </url>
</urlset>

robot.ts 파일도 마친가지로 app 폴더에 아래와 같이 생성할 경우

import type { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: "*",
      allow: "/",
      disallow: "/private/",
    },
    sitemap: "https://acme.com/sitemap.xml",
  };
}

다음과 같이 변환됩니다.

User-Agent: *
Allow: /
Disallow: /private/

Sitemap: https://acme.com/sitemap.xml

저는 Next.js + MDX로 포스팅 기능 구현하기 게시글에서 작성했었던 모든 MDX파일의 slug와 Metadata를 반환하는 getAllPostMeta() 메서드를 통해 게시글이 추가될때마다 sitemap.xml에 게시글 경로가 동적으로 추가될 수 있도록 코드를 작성했습니다.

import type { MetadataRoute } from "next";
import { getAllPostMeta } from "@/lib/mdx";
import { baseURL } from "@/constants/path";

export default function sitemap(): MetadataRoute.Sitemap {
  const posts = getAllPostMeta().map((post) => ({
    url: `${baseURL}/post/${post.slug}`,
    lastModified: new Date(post.postMetaData.date),
  }));

  const routes: MetadataRoute.Sitemap = ["/", "/about", "/post"].map(
    (route) => ({
      url: `${baseURL}${route}`,
      lastModified: new Date().toISOString(),
    }),
  );

  return [...routes, ...posts];
}

robots.ts는 다음과 같이 작성해줬습니다.

import type { MetadataRoute } from "next";
import { baseURL } from "@/constants/path";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: "*",
      allow: "/",
    },
    sitemap: `${baseURL}/sitemap.xml`,
  };
}

Google Search Console에 웹사이트 등록하기

블로그의 seo를 설정한 후에는 Google Search Console에 등록해주는 것이 좋습니다.

Google Search Console은 Google에서 무료로 제공하는 서비스로, 사용자가 사이트의 Google 검색결과 인지도를 모니터링하고 관리하며 문제를 해결하도록 도와줍니다. Search Console에 가입하지 않아도 Google 검색결과에 포함되지만 Search Console에 가입하면 Google의 입장에서 사이트를 파악하고 개선할 수 있습니다.

웹사이트를 Google Search Console에 등록하지 않아도 크롤러가 언젠가는 사이트를 찾아 분석하지만, Google Search Console에 등록해놓으면 색인 생성 여부, 검색 트래픽 데이터 같은 정보를 제공해줍니다.

먼저 등록해주려면 속성 추가를 해줘야 합니다.

gsc_add_property

속성 추가하기 버튼을 클릭하게 되면 도메인 혹은 URL 접두어를 입력하라고 나오는데 저는 URL 접두어로 제 사이트를 등록했습니다.

gsc_select_property

웹사이트 속성 등록이 완료되면, Sitemaps 탭에서 sitemap.xml을 제출해주시면 됩니다. sitemap.xml을 제출하면 Googlebot이 사이트 구조를 더 빠르게 이해하고 색인 작업을 수행할 수 있습니다.

gsc_add_sitemap

이렇게 등록하고 대략 1~2일 정도 지나고 나면 구글서치콘솔에 통계가 뜨기 시작합니다.