본문 바로가기
프로젝트 답지

next.js에서 seo최적화로 커뮤니티 활성화 방안?

by 띠리에이터 2025. 4. 16.

🧭 Next.js와 SEO 최적화를 통한 커뮤니티 활성화 전략

커뮤니티 웹사이트의 성공을 결정짓는 핵심 요소 중 하나는 사용자 유입이다. 아무리 좋은 콘텐츠를 갖추고 있어도, 검색 결과에 노출되지 않는다면 방문자는 늘지 않는다.
SEO(Search Engine Optimization) 최적화는 커뮤니티 활성화를 위한 필수 전략이다.

이번엔 Next.js 기반 커뮤니티 웹사이트에서 SEO 최적화를 해봐야겠다. 


1️⃣ SEO란?

SEO(Search Engine Optimization)는 검색 엔진(구글, 네이버 등)이 웹사이트를 잘 이해하고, 검색 결과에 상위 노출되도록 구조를 최적화하는 작업임!

  • 📈  검색엔진 결과에서 상위 노출 → 자연 트래픽 증가
  • ❗ 아무리 좋은 글이라도 검색에 걸리지 않으면 유입은 없음.

2️⃣ Next.js의 SEO 친화적인 구조

Next.js는 pre-rendering을 기본으로 제공하는 프레임워크로, SEO에 강한 구조를 갖추고 있다.
특히 서버컴포넌트를 활용하면 페이지 메타 정보를 더 정교하게 제어 가능


3️⃣ 실제 구현 사례

🧱 3.1 게시판 메인 페이지 SEO 적용. 

  • 이 페이지는 use 훅을 사용하는 클라이언트 컴포넌트였다.  
  • 처음엔 단순하게 페이지에 metadata를 적용하면 meta의 타이틀이 적용되는 줄 알았지만 

  • metadata는 서버 컴포넌트에서만 적용가능!
  • metadata는 서버 컴포넌트에서만 사용할 수 있기 때문에 별도의 layout.tsx 파일을 생성해 처리했다.
import { Metadata } from 'next';

export const metadata: Metadata = {
  title: '게시판',
  description: '게시판 페이지',
};

const BoardLayout = ({ children }: { children: React.ReactNode }) => {
  return <>{children}</>;
};

export default BoardLayout;

 

  • 일단 간단하게 타이틀 적용!


📝 3.2 게시판 상세 페이지에 동적 SEO 적용

  • 게시글 타이틀과 카테고리를 메타데이터로 직접 반영하고자 했다.
  • Next.js에서 제공하는 generateMetadata 함수를 활용해 동적 메타데이터를 구현.
  • 기존에 클라이언트컴포넌트였던 상세 페이지를 서버 컴포넌트로 변경
  • 데이터를 렌더링 해줬던 컴포넌트 코드는 하위 컴포넌트로 넘겨줬다. 
export const generateMetadata = async ({
  params,
}: {
  params: { boardId: string };
}) => {
  const boardDetailData: BorardDetailResponseType = await boardDetailGetDatas(
    params.boardId,
  );

  return {
    title: boardDetailData.result.title,
    description: boardDetailData.result.category,
    openGraph: {
      title: boardDetailData.result.title,
      description: boardDetailData.result.category,
      url: `${process.env.NEXT_PUBLIC_URL}/board/${params.boardId}`,
      images: '/icon/widelogo.png',
    },
  };
};
const BoardDetailPage = ({ params }: { params: { boardId: string } }) => {
  return <BoardDetailClient boardId={params.boardId} />;
};

export default BoardDetailPage;

🧠 이 구조를 통해 구글이나 SNS 공유 시에도 게시글 제목/카테고리가 제대로 노출되도록 개선했다.


✅ 결과

  • 일단 게시판 페이지에 메타태그가 타이틀 설정
  • 상세 페이지는 OpenGraph 정보까지 포함




찾아보니 단순히 metadata만 적용한다고 되는게 아니라 웹사이트 내에 robots와 sitemap파일을 설정해줘야한다. 

🤖 robots.txt란?

  • 역할: 검색 엔진 크롤러(봇)에게 “어떤 페이지를 크롤링해도 좋고, 어떤 페이지는 제외해 달라”는 지침을 제공하는 파일
  • 위치: 웹사이트 루트(/robots.txt)
  • 주요 요소:
    • User-agent: 지침을 적용할 크롤러(예: *는 모든 크롤러)
    • Allow / Disallow: 허용·비허용 경로 지정
    • Sitemap: 크롤러가 참고할 sitemap 파일의 URL
  • 왜 필요한가?
    • 불필요한 페이지(관리자 페이지, 내부 API 등)를 크롤링 대상에서 제외
    • 검색엔진의 크롤링 예산을 핵심 콘텐츠에 집중하게 유도
    • sitemap 위치를 알려줘서 크롤링 효율을 높임

🗺️ sitemap.xml이란?

  • 역할: 사이트 내 모든(또는 주요) URL을 구조화된 XML 형식으로 나열해, 검색엔진에 “어떤 페이지들이 있고, 언제 수정되었는지” 알려 주는 맵
  • 위치: 웹사이트 루트(/sitemap.xml) 또는 robots.txt에서 참조
  • 주요 요소:
    • <loc>: 페이지 URL
    • <lastmod>: 최종 수정일
    • <changefreq>: 페이지 변경 빈도(예: daily, weekly)
    • <priority>: 페이지 중요도(0.0~1.0)
  • 왜 필요한가?
    • 검색엔진이 숨겨진 깊숙한 URL까지 놓치지 않고 크롤링하도록 도움
    • 동적 페이지(게시판 상세, 카테고리 페이지 등)도 빠짐없이 색인할 수 있게 함
    • <lastmod> 기반으로 변경된 페이지만 우선 크롤링하여 효율 최적화
 

위 두 파일을 올바르게 설정해 두면,

  • 크롤러에게 “이 사이트에는 이런 페이지가 있어요, 그리고 /admin은 크롤링하지 말아 주세요”라고 명확히 알려줄 수 있고,
  • 검색엔진이 모든 중요한 URL을 빠짐없이 수집해 좋은 SEO 성과를 기대할 수 있다.

seo설정을 안 한 상태에서 네이버 서치 어드바이저를 통해 내 웹사이트 간단 체크를 해보니 

robots.txt파일 설정을 안해줘서 존재하지 않는다고 나옴! 

 

1️⃣ app폴더 내에 robots.ts 파일을 생성후 next.js 공식문서에 나와있는 기본 설정을 따라줬다. 

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: 허용·비허용 경로 지정, 
  • 관리자 페이지는 크롤러가 크롤링 할 수 없도록 제외설정을 해놓음, 
  • Sitemap: 크롤러가 참고할 sitemap 파일의 URL

 

https://nextjs.org/docs/app/api-reference/file-conventions/metadata/robots

 

Metadata Files: robots.txt | Next.js

API Reference for robots.txt file.

nextjs.org

 

2️⃣ 다음 sitemap설정 

import type { MetadataRoute } from 'next';

export default function sitemap(): MetadataRoute.Sitemap {
  return [
    {
      url: 'https://acme.com/',
      lastModified: new Date(),
      changeFrequency: 'monthly',
      priority: 0.8,
    },
    {
      url: 'https://acme.com/board',
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 1,
    },
  ];
}

 

  • sitemap은 정적과 동적으로 생성 가능하다. 
  • 일단 기본적인 것만 보기 위해서 페이지 2개만 정적으로 설정해줬음. 

✅ 적용 결과 확인

  • 네이버 서치 어드바이저에서 /robots.txt와 /sitemap.xml이 정상 인식됨

 

3️⃣ 게시판 상세 데이터를 sitemap에 동적생성 해야함

import type { MetadataRoute } from 'next';
import { sitemapBoardList } from './(main)/board/api';
import { boardSitemapType } from '../utils/type';

const defaultSitemap: MetadataRoute.Sitemap = [
  {
    url: `${BASE_URL}/`,
    lastModified: new Date(),
    changeFrequency: 'monthly',
    priority: 0.8,
  },
  {
    url: `${BASE_URL}/board`,
    lastModified: new Date(),
    changeFrequency: 'daily',
    priority: 1,
  },
];

const sitemap = async (): Promise<MetadataRoute.Sitemap> => {
  const limit = 1000;
  const offset = 0; 

  const sitemapBoardData = await sitemapBoardList({ offset, limit });

  const dynamicPages: MetadataRoute.Sitemap = sitemapBoardData.map(
    (board: boardSitemapType) => {
      return {
        url: `${BASE_URL}/board/${board.boardId}`,
        lastModified: new Date(board.updatedAt),
        changeFrequency: 'weekly',
        priority: 0.7,
      };
    },
  );

  return [...defaultSitemap, ...dynamicPages];
};
export default sitemap;

 

 

  • defaultSitemap
    • 홈(/)과 /board 목록 페이지를 정적으로 분리, 
  • sitemap 함수
    • limit, offset 으로 한 번에 조회할 게시글 범위 설정
    • 각 board 객체를 Next.js가 요구하는 SitemapFile 형식으로 변환
    • defaultSitemap 과 합쳐서 최종 Sitemap 배열을 반환
    • => /sitemap.xml을 동적으로 생성. 

 

 

❗ 이제 배포 후 확인해야 해서 빌드를 하니 에러가 발생함.. 

Export encountered errors on following paths:
/sitemap.xml/route: /sitemap.xml

❗ 오류가 생긴 이유

  • Next.js App Router 기본값(dynamic = 'auto')으로 정적 생성을 시도
  • sitemap.ts 내부에서 상대경로(/sitemap_boards)로 백엔드 API 호출 →
    빌드 시점에는 Next.js 서버(API)가 실행 중이 아니어서 데이터 조회 실패
  • 메타데이터 전용 라우트(app/sitemap.ts, app/robots.ts 등)는 기본값이 무조건 빌드 타임 SSG로 미리 생성한다. 

생각보다 간단한 해결 방법이 있었다. 

export const dynamic = 'force-dynamic';

 


Next.js App Router에서는 페이지를 빌드 타임에 미리 HTML로 생성하거나,
런타임에 매번 서버에서 HTML을 만드는(SSR) 방식을 혼합해서 사용한다.
기본값(dynamic = 'auto')일 때는 가능하면 빌드 타임에 생성해 두고, 필요할 때(동적 데이터 호출 등)만 런타임으로 전환하는 방식.

  • sitemap 파일 상단에 해당 코드를 추가
  • 정적 생성(SSG)을 완전히 건너뛰고
  • 오직 런타임(SSR)에만 /sitemap.xml 경로를 처리하도록 강제하게 된다.

 

✅ sitemap이 동적으로 잘 생성된 것을 확인할 수 있다. 

 

 

참고

 

https://github.com/vercel/commerce/issues/1010?utm_source=chatgpt.com

 

Sitemap.xml prerendering error on all preview deployments to Vercel · Issue #1010 · vercel/commerce

When pushing any branch except main, I get the following error on preview deployments to Vercel: Error occurred prerendering page "/sitemap.xml". Read more: https://nextjs.org/docs/messages/prerend...

github.com

 

https://www.reddit.com/r/nextjs/comments/1aggwrs/sitemap_regeneration_on_cms_post_update/?utm_source=chatgpt.com

 

From the nextjs community on Reddit: Sitemap regeneration on CMS post update

Explore this post and more from the nextjs community

www.reddit.com

 

 

 


분명히 게시판 상세가 url/sitemap.xml확인하면 사이트맵 생성이 잘 된 걸 확인 할 수 있는데 구글서치콘솔에 가면 참조 안된다고 나옴, 

페이지 가져오기는 성공했는데 색인 생성이 안됨?

 

흠.. 

 

그래서 서치콘솔에 직접 sitemap url등록했더니 html형식이라고 나옴, 그래서 안되는건가보다 

 

1. 일단 미들웨어에서 sitemap.xml접근 못하게 막은거 해제하기

2. next-sitemap 로 바꿔보기??