Next.js 검색 엔진 최적화 (SEO)

Frontend/Next.js

Pages Router

Head

페이지 별로 Head 컴포넌트 안에 작성하여 SEO 관련 메타 데이터를 설정할 수 있다.

import Head from "next/head";

export default Page() {
  return (
    <>
      <Head>
        <title>타이틀</title>
        <meata property="og:image" content={썸네일 주소} />
        <meata property="og:title" content={타이틀} />
        <meata property="og:description" content={설명} />
      </Head>
      <div>
        // ...
      </div>
    </>
  );
}

 

Fallback 상태에서의 SEO 처리

동적 라우팅을 사용하는 페이지(예: 아이템별 상세 페이지)에서 fallback:true를 설정했을 때, 지정하지 않은 경로에 대해 SSR과 유사하게 동작한다.

 

이때 초기 HTML에 SEO 관련 메타 데이터가 포함되지 않는 문제가 발생할 수 있는데, 이를 방지하기 위해 fallback 상태에서도 기본적인 SEO 설정을 제공하는 것이 중요하다.

import { GetStaticPropsContext, InferGetStaticPropsType } from "next";
import Head from "next/head";
import { useRouter } from "next/router";
import fetchOneBook from "@/lib/fetch-one-book";
import styles from "./[id].module.css";

export const getStaticPaths = async () => {
  return {
    paths: [
      { params: { id: "1" } },
      { params: { id: "2" } },
      { params: { id: "3" } },
    ],
    fallback: true,
  };
};

export const getStaticProps = async (context: GetStaticPropsContext) => {
  const { id } = context.params!;
  const book = await fetchOneBook(Number(id));

  if (!book) {
    return {
      notFound: true,
    };
  }

  return {
    props: {
      book,
    },
  };
};

export default function Page({
  book,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  const router = useRouter();

  // fallback 상태일 때, 기본적인 SEO 메타 데이터를 설정
  if (router.isFallback) {
    return (
      <>
        <Head>
          <title>한입북스</title>
          <meta property="og:image" content="/thumbnail.png" />
          <meta property="og:title" content="한입북스" />
          <meta
            property="og:description"
            content="한입 북스에 등록된 도서들을 만나보세요."
          />
        </Head>
        <div>로딩중입니다.</div>
      </>
    );
  }

  if (!book) return "문제가 발생했습니다. 다시 시도하세요.";

  const { title, subTitle, description, author, publisher, coverImgUrl } = book;

  return (
    <>
      <Head>
        <title>{title}</title>
        <meta property="og:image" content={coverImgUrl} />
        <meta property="og:title" content={title} />
        <meta property="og:description" content={description} />
      </Head>
      {/* 페이지 내용 */}
    </>
  );
}

 

App Router

Metadata

앱 라우터에서는 페이지 라우터의 Head 컴포넌트를 대체하는 metadata 객체를 이용해 페이지의 메타데이터를 설정할 수 있다.

import { Metadata } from 'next';

export const metadata: Metadata = {
  title: "타이틀",
  description: "설명"
  openGraph: {
    title: "타이틀,
    description: "설명",
    images: ["썸네일 주소"],
  },
};

export default function Page() {
  return (
    // 페이지 컨텐츠
  );
}

 

동적 메타데이터 생성

동적 라우트나 검색 페이지와 같이 페이지 내용에 따라 메타 데이터가 변경되어야 하는 경우, generateMetadata 함수를 사용할 수 있다.

검색 페이지 예시

아래의 예제는 URL의 검색 파라미터를 사용하여 동적으로 메타데이터를 생성한다.

import { Metadata } from 'next';

type PropsType = {
  searchParams: {
    q?: string;
  };
};

export function generateMetadata({ searchParams }: PropsType): Metadata {
  const query = searchParams.q || '전체';
  return {
    title: `${query} : 검색`,
    description: `${query} 검색 결과입니다.`,
    openGraph: {
      title: `${query} : 검색`,
      description: `${query} 검색 결과입니다.`,
      images: ["/thumbnail.png"],
    },
  };
}

export default function Page({ searchParams }: PropsType) {
  // 검색 결과 렌더링
}

 

상세 페이지 예시

아래의 예제는 도서 id를 이용하여 서버에서 도서 정보를 가져온 후, 그 정보를 바탕으로 메타데이터를 동적으로 생성한다.

import { Metadata } from 'next';

type PropsType = {
  params: {
    id: string;
  };
};

export async function generateMetadata({
  params,
}: PropsType): Promise<Metadata> {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book/${params.id}`
  );

  if (!response.ok) {
    throw new Error('도서 정보를 가져오는데 실패했습니다');
  }

  const book = await response.json();

  return {
    title: `${book.title} - 한입북스`,
    description: book.description,
    openGraph: {
      title: `${book.title} - 한입북스`,
      description: book.description,
      images: [book.coverImgUrl],
    },
  };
}

export default function Page({ params }: PropsType) {
  // 상세 정보 렌더링
}

'Frontend > Next.js' 카테고리의 다른 글

Next.js의 데이터 페칭 방식  (0) 2025.11.13
React Server Component  (0) 2025.11.13
Next.js 페이지 라우터의 렌더링 방식  (0) 2025.11.13
Next.js의 프리 페칭 (Pre-fetching)  (0) 2025.11.13
Next.js의 레이아웃 설정  (0) 2025.11.09
'Frontend/Next.js' 카테고리의 다른 글
  • Next.js의 데이터 페칭 방식
  • React Server Component
  • Next.js 페이지 라우터의 렌더링 방식
  • Next.js의 프리 페칭 (Pre-fetching)
고견
고견
개발 자국 남기기
  • 고견
    개발자국
    고견
  • 전체
    오늘
    어제
    • 분류 전체보기 (157) N
      • Frontend (29)
        • Next.js (16)
        • JavaScript (7)
      • CS (19) N
        • 자료구조 (9)
        • 알고리즘 (5)
        • 운영체제 (4) N
        • 네트워크 (1) N
      • TIL (93)
      • Dev Log (16)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    클래스
    타입 좁히기
    cs50
    Pages Router
    제네릭
    자료구조
    generic
    트러블 슈팅
    앱 라우터
    ai 감성 일기장
    함수 타입
    Next.js
    문자열
    typescript
    바닐라 자바스크립트
    CS
    배열
    App Router
    useState
    Trouble Shooting
    react
    페이지 라우터
    C
    javascript
    알고리즘
    emotion diary
    memory
    인터페이스
    Spa
    algorithm
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
고견
Next.js 검색 엔진 최적화 (SEO)
상단으로

티스토리툴바