📖 11 분 읽기

SEO를 위한 Next.js vs Astro (2026): 무엇을 선택해야 할까?

렌더링, 성능, i18n, 그리고 각각이 빛을 발하는 시점까지 — 과장 없이 실용적으로 비교한 Next.js와 Astro의 SEO 가이드.

  • Next.js
  • Astro
  • Comparison

Next.js와 Astro 둘 다 충분히 잘 랭킹될 수 있습니다. Google은 어느 프레임워크의 서버 렌더링 HTML이든 군말 없이 색인하며, “SEO에는 어떤 프레임워크가 더 나은가”를 “Google이 은밀히 선호하는 쪽은 어디인가”로 읽는다면 그건 잘못된 질문입니다. 옳은 질문은 더 좁고 더 유용합니다. 당신이 만들고 있는 사이트의 종류를 고려했을 때, 어느 프레임워크가 좋은 SEO를 가장 저항이 적은 길로 만들어 주는가?

이 글은 개발자 대 개발자의 비교입니다. 실제 렌더링 파이프라인, 기본값으로 브라우저에 전달되는 것, Core Web Vitals가 어떻게 갈리는지, 그리고 각 프레임워크가 화려하진 않지만 승부를 가르는 작업인 hreflang과 구조화된 데이터를 어떻게 처리하는지를 살펴봅니다. 파벌주의는 빼고 — 트레이드오프와 코드만 다룹니다.

TL;DR — 한 줄 결론

콘텐츠나 마케팅 사이트(블로그, 문서, 랜딩 페이지, 프로그래매틱 SEO)를 만들고 있다면, Astro는 기본값으로 거의 JS가 없는 HTML을 제공하며 실수로 Core Web Vitals를 망칠 기회를 최소화합니다. 콘텐츠 레이어가 덧붙은 인터랙티브 애플리케이션(대시보드, 마케팅 표면이 있는 SaaS, 개인화가 많은 이커머스)을 만들고 있다면, Next.js는 앱 전체에 하나의 멘탈 모델을 제공하고, 동적이어야 하는 페이지를 위한 성숙한 SSR/ISR을 제공합니다.

항목AstroNext.js (App Router)
기본 렌더링SSG (사전 렌더링된 HTML)SSR / RSC (요청마다 서버 렌더링)
브라우저로 가는 기본 JS~0 KB (아일랜드만)React 런타임 + RSC 페이로드
동적 렌더링SSR 어댑터, 온디맨드SSR, ISR, 스트리밍, RSC — 일급(first-class)
기본 Core Web Vitals우수 (하이드레이션할 것이 적음)양호하나 퇴보하기 쉬움
i18n내장 라우팅 + 수동 hreflangi18n 설정 (Pages) / 수동 (App) + hreflang
구조화된 데이터.astro 템플릿에 인라인컴포넌트 내 인라인 / generateMetadata
적합한 대상콘텐츠 및 마케팅 사이트콘텐츠를 가진 인터랙티브 앱
학습 곡선HTML/JS를 안다면 낮음보통 (RSC 멘탈 모델)

어느 쪽을 선택해도 랭킹 페널티는 아닙니다. 차이는 페이지를 빠르고 크롤링 가능하게 유지하는 데 얼마나 많은 경계가 필요한지에 있습니다.

🧑‍💻 개발자 시각: 프레임워크 자체가 랭킹을 깎아먹는 경우는 드뭅니다. 랭킹을 잃게 만드는 것은 한 문단의 텍스트를 렌더링하려고 400 KB짜리 JS 번들을 보내는 일, 또는 인터랙티브 위젯 하나만 필요한데 페이지 전체를 하이드레이션하는 일입니다. Astro는 그 실수를 어렵게 만들고, Next.js는 쉽게 만듭니다 — 하지만 그것을 피할 도구 또한 함께 줍니다.

렌더링 모델

SEO는 하나의 질문에서 시작합니다. 크롤러가 초기 HTML 응답에서 무엇을 받는가? Google은 JavaScript를 실행하지만, 렌더링은 지연되고 예산이 정해진 두 번째 물결입니다 — 그래서 하이드레이션 이후에만 존재하는 콘텐츠는 렌더 큐가 노출해 주기를 거는 도박이 됩니다. (이 파이프라인은 JavaScript SEO 가이드에서 깊이 다룹니다.)

Astro: 정적 우선 + 아일랜드

Astro의 기본값은 **정적 사이트 생성(static site generation)**입니다. 빌드 타임에 .astro 컴포넌트를 실행해 완전한 HTML을 생성하며, 그리고 — 이게 핵심인데 — client:* 디렉티브로 컴포넌트를 명시적으로 하이드레이션에 참여시키지 않는 한 프레임워크 JavaScript를 제거합니다. 이것이 “아일랜드 아키텍처”입니다. 페이지는 정적 HTML이고, 인터랙티브한 부분만 하이드레이션된 아일랜드가 됩니다.

---
// src/pages/blog/[slug].astro — runs at build time, never ships to the client
const { slug } = Astro.params;
const post = await getPost(slug);
---
<article>
  <h1>{post.title}</h1>
  <div set:html={post.html} />
  <!-- Only this counter ships JS. The rest is inert HTML. -->
  <LikeButton client:visible postId={post.id} />
</article>

크롤러는 첫 바이트에서 완전히 형성된 글을 받습니다. 기다릴 두 번째 렌더 물결이 없습니다 — 렌더링할 것이 남아 있지 않기 때문입니다. 콘텐츠에 있어서는 이보다 더 좋을 수 없습니다. 라우트가 정말로 요청별 데이터를 필요로 할 때 Astro는 어댑터(@astrojs/node, Cloudflare, Vercel)를 통해 SSR도 할 수 있으므로, “정적 우선”이 “정적 전용”을 뜻하는 건 아닙니다.

Next.js: 서버 컴포넌트와 요청별 렌더링

App Router를 쓰는 Next.js는 기본값이 React Server Components입니다. 페이지는 서버(또는 정적 라우트의 경우 빌드 타임)에서 렌더링되어 브라우저로 HTML을 보내고, 더불어 React가 클라이언트 컴포넌트를 재조정(reconcile)하고 하이드레이션할 수 있게 해 주는 RSC 페이로드를 보냅니다. 초기 응답에서 HTML을 받으니 크롤링에는 좋지만, 페이지는 React 런타임도 함께 보내고 클라이언트에서 다시 하이드레이션합니다.

Next.js는 더 풍부한 렌더링 모드 메뉴를 제공하며, 라우트별로 선택합니다.

  • 정적(SSG)export const dynamic = 'force-static' 또는 동적 데이터가 아예 없으면; 빌드 타임에 사전 렌더링됩니다.
  • SSR — 사용자, 지역, 시간에 따라 바뀌는 콘텐츠를 위해 요청마다 렌더링됩니다.
  • ISRexport const revalidate = 3600; 정적으로 서빙하고 백그라운드에서 재생성합니다. 자주 바뀌지만 요청마다 바뀌지는 않는 대규모 콘텐츠 사이트에 탁월합니다.
// app/blog/[slug]/page.tsx — Server Component, runs on the server
export const revalidate = 3600; // ISR: re-generate at most hourly

export async function generateStaticParams() {
  const posts = await getAllSlugs();
  return posts.map((slug) => ({ slug }));
}

export default async function Page({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug);
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.html }} />
    </article>
  );
}

💡 팁: SEO 관점에서 위험한 Next.js 패턴은 주요 콘텐츠를 useEffect에서 가져오는 클라이언트 측 'use client' 페이지입니다. 그 콘텐츠는 초기 HTML에서 보이지 않으며 전적으로 Google의 렌더 물결에 의존합니다. 라우트의 주요 콘텐츠를 서버 렌더링할 수 있다면, 서버 렌더링하세요.

실용적 결론: 둘 다 현대적이고 권장되는 구성에서는 기본값으로 색인 가능한 HTML을 전달합니다. Astro는 클라이언트 프레임워크 없이 전달하고, Next.js는 하이드레이션 단계와 함께 전달합니다. 이 한 가지 차이가 뒤따르는 대부분의 것을 좌우합니다.

성능 & Core Web Vitals

Core Web Vitals(LCP, INP, CLS)는 랭킹 신호이며, 더 중요하게는 실제 사용자가 좋은 경험을 하는지를 가늠하는 대리 지표입니다. 프레임워크 결정은 얼마나 많은 JavaScript가 전달되고, 페이지가 인터랙티브해지기 전에 그중 얼마가 실행되어야 하는가에서 가장 뚜렷하게 드러납니다.

기본 페이로드

전형적인 Astro 콘텐츠 페이지는 아일랜드를 위한 JS만 전달합니다 — 순수 글에서는 종종 말 그대로 0입니다. 전형적인 Next.js App Router 페이지는 React 런타임에 더해 RSC 플라이트 페이로드, 그리고 클라이언트 컴포넌트 코드까지 전달합니다. 그건 “비대함(bloat)“이 아니라 React 앱의 비용입니다 — 하지만 95%가 산문인 페이지에서는 쓰지도 않는 인터랙티비티에 비용을 치르는 셈입니다.

페이지 유형Astro 일반 클라이언트 JSNext.js 일반 클라이언트 JS
위젯 없는 정적 글~0 KB~80–110 KB (런타임 + RSC)
글 + 댓글 위젯 하나~15–30 KB (아일랜드 하나)~90–130 KB
고도로 인터랙티브한 대시보드무겁게 하이드레이션되면 Next와 비슷~150 KB+ (자기 홈그라운드)

수치는 의존성에 따라 달라집니다 — next build 출력이나 Astro의 번들 리포트로 직접 빌드를 측정하세요 — 하지만 그 형태는 일관됩니다. Astro는 0에 가깝게 시작해 요청한 곳에만 JS를 더하고, Next는 런타임 바닥선에서 시작해 거기서부터 커집니다.

하이드레이션 비용과 INP

LCP는 대체로 가장 큰 요소를 빠르게 그리는 것에 관한 일입니다 — 둘 다 서버 렌더링할 때 이를 잘 해냅니다. 더 날카로운 분기점은 메인 스레드 작업을 벌하는 INP(Interaction to Next Paint)입니다. 큰 React 트리를 하이드레이션하면 메인 스레드가 막히고, 저사양 모바일에서는 첫 인터랙션이 지연됩니다. Astro의 아일랜드는 독립적으로 그리고 지연적으로(client:visible, client:idle) 하이드레이션되므로 메인 스레드가 더 오래 자유롭게 유지됩니다.

⚠️ 주의: 빠른 프레임워크가 느린 사이트를 구해 주지는 않습니다. 최적화되지 않은 히어로 이미지, 렌더링을 막는 서드파티 스크립트, 웹폰트로 인한 레이아웃 시프트는 어느 프레임워크에서든 CWV를 망가뜨립니다. 프레임워크를 탓하기 전에 실제 감사를 돌리세요(PageSpeed Insights, Lighthouse, 또는 우리 Core Web Vitals 가이드).

빌드된 페이지에서 빠르게 점검해 실제로 전달되는 것을 확인하세요.

# Count bytes of JS the page actually requests
curl -s https://your-site.com/blog/some-post/ \
  | grep -oE 'src="[^"]+\.js"' | wc -l

# Or inspect the initial HTML the crawler sees — is the content there?
curl -s https://your-site.com/blog/some-post/ | grep -c "<h1"

콘텐츠 vs 앱

여기서 결정은 대개 저절로 풀립니다. 당신의 사이트가 무엇인지 물어보세요.

콘텐츠 및 마케팅 사이트는 Astro로 이깁니다. 블로그, 문서, 체인지로그, 랜딩 페이지, 그리고 프로그래매틱 SEO 페이지(수백 또는 수천 개의 템플릿 URL)는 대부분 텍스트와 이미지에 가끔의 인터랙티비티가 더해진 것입니다. Astro의 콘텐츠 컬렉션은 타입이 지정된 frontmatter, Markdown/MDX, 그리고 JS가 없는 출력을 제공합니다. CMS에 준하는 셋업의 작성 편의성과 손으로 쓴 HTML의 성능을 동시에 얻습니다.

Astro content collection — typed, build-time, zero client JS
  src/content/
    blog/        ← MDX + frontmatter schema (Zod)
    config.ts    ← defineCollection() validates every post at build

인터랙티브 애플리케이션은 Next.js로 이깁니다. 핵심 제품이 앱이고 — 인증된 대시보드, 실시간 데이터, 복잡한 폼, 상태를 가진 흐름 — 그것을 둘러싼 마케팅이나 콘텐츠 표면에 SEO가 중요하다면, Next.js는 전체를 하나의 프레임워크, 하나의 배포로 구축하게 해 줍니다. 두 스택(Astro 마케팅 사이트 + 별도의 React 앱)을 돌리는 일과 그 사이의 라우팅/인증 이음새를 피할 수 있습니다. App Router의 ISR과 SSR은 또한 순수 SSG 모델이라면 끊임없이 다시 빌드하게 만들었을 진정으로 동적이고 SEO와 관련된 페이지(실시간 가격이 있는 제품 페이지, 위치 페이지)를 처리합니다.

회색 지대는 약간의 동적 요소를 가진 이커머스와 대규모 콘텐츠 사이트입니다. 둘 다 됩니다. 페이지가 대규모로 요청별 상태(재고, 개인화)를 반영해야 한다면 Next.js를, 카탈로그가 대부분 정적이고 몇 안 되는 동적 라우트는 다시 빌드하거나 온디맨드 SSR을 쓸 수 있다면 Astro를 선택하세요.

i18n & 구조화된 데이터

국제 SEO는 hreflang에서 흥하고 망하며, 리치 결과(rich results)는 JSON-LD에 달려 있습니다. 어느 프레임워크도 이것을 완전히 대신 해 주지는 않습니다 — 마크업은 당신의 몫입니다 — 하지만 라우팅 지원은 다릅니다.

hreflang

두 프레임워크 모두 상호적인(reciprocal) hreflang 링크 태그를 당신이 내보낼 것을 기대합니다. Astro는 대체(alternate) URL 생성을 간단하게 만들어 주는 내장 i18n 라우팅(로케일 접두사, 기본 로케일 설정)을 갖추고 있고, Next.js Pages Router는 i18n 설정이 있었던 반면 App Router는 폴더 기반 로케일 세그먼트(app/[locale]/...)에 next-intl 같은 라이브러리를 더하는 방향으로 밀어붙입니다. 두 경우 모두 태그는 당신이 직접 생성합니다.

<!-- The same set of tags belongs on every language version of a page -->
<link rel="alternate" hreflang="en" href="https://ex.com/en/blog/post/" />
<link rel="alternate" hreflang="fr" href="https://ex.com/fr/blog/post/" />
<link rel="alternate" hreflang="x-default" href="https://ex.com/en/blog/post/" />

💡 팁: 가장 흔한 hreflang 버그는 비상호적 주석입니다 — 페이지 A는 B를 가리키는데 B는 A를 가리켜 돌아오지 않는 경우입니다. 하나의 진실 공급원(로케일 → URL 맵)에서 전체 클러스터를 생성하고 모든 변형(variant)에 렌더링하세요. 깊이 있는 분석은 국제 SEO 가이드에 있습니다.

구조화된 데이터 (JSON-LD)

JSON-LD는 그저 script 태그이므로 두 프레임워크는 본질적으로 동일하게 처리합니다 — 차이는 오직 그것을 어디에 두느냐뿐입니다. Astro에서는 템플릿에 인라인하고, Next.js에서는 컴포넌트에서 렌더링하거나 generateMetadata에서 빌드합니다.

---
// Astro: build the object in frontmatter, render as a script tag
const schema = {
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  headline: post.title,
  datePublished: post.pubDate.toISOString(),
};
---
<script type="application/ld+json" set:html={JSON.stringify(schema)} />
// Next.js: render JSON-LD from a Server Component
export default function Page({ post }) {
  const schema = {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    headline: post.title,
    datePublished: post.pubDate,
  };
  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
    />
  );
}

프레임워크와 무관하게 Google의 Rich Results Test로 출력을 검증하세요 — 필수 속성이 빠지면 조용히 실패하고 리치 결과를 영영 얻지 못합니다.

언제 어느 쪽을 고를까

시나리오별 구체적 가이드입니다.

  • 블로그, 문서, 또는 마케팅 사이트Astro. JS 0 기본값, 콘텐츠 컬렉션, 최소한의 규율로 얻는 최선의 CWV.
  • 대규모 프로그래매틱 SEO(수천 개의 템플릿 페이지) → 페이지가 거의 정적이면 Astro; 잦은 또는 요청별 신선함이 필요하면 ISR을 쓰는 Next.js.
  • 마케팅 사이트와 앱을 가진 SaaS → 하나의 스택을 원하면 Next.js; 마케팅 페이지 속도를 극대화하고 싶고 배포 두 개를 감수할 수 있다면 마케팅용 Astro + 당신의 앱 프레임워크.
  • 이커머스 → 대규모로 요청별 재고/가격/개인화가 필요하면 Next.js; 대부분 정적인 카탈로그라면 Astro.
  • SEO가 부차적인 고도로 인터랙티브한 앱Next.js. 여기서 SEO는 문제가 안 됩니다 — DX를 기준으로 고르세요.
  • React를 깊이 알고 빠르게 출시하는 팀 → 클라이언트 JS에 대한 규율을 지키는 한, Next.js는 콘텐츠에서도 마찰을 낮춥니다.

🧑‍💻 개발자 시각: 인기 있고 전적으로 타당한 패턴은 둘 다 쓰는 것입니다 — 마케팅/블로그 서브도메인이나 /blog 경로에는 Astro, app.*에는 Next.js(또는 당신의 SPA). SEO가 중요한 곳에는 Astro의 콘텐츠 성능을, 그렇지 않은 곳에는 React의 인터랙티비티를 얻습니다. 비용은 빌드 두 개와 공유 디자인 시스템입니다.

마무리

Google이 보상하는 프레임워크를 찾는 일은 그만두세요 — 그런 건 없습니다. Next.js와 Astro 둘 다 현대적인 방식으로 구성하면 크롤링 가능하고 랭킹 가능한 HTML을 만들어 냅니다. 진짜 결정은 기본 동작과 실패 모드에 관한 것입니다. Astro는 빠르고 JS가 0인 콘텐츠 페이지를 기본값이자 게으른 길로 만들고, Next.js는 통합된 인터랙티브 애플리케이션을 기본값으로 만들면서, 규율을 투자할 때 동적 페이지를 SEO 친화적으로 유지할 렌더링 모드를 제공합니다.

사이트가 콘텐츠 그 자체일 때는 Astro를 고르세요. 사이트가 콘텐츠도 가진 앱일 때는 Next.js를 고르세요. 그리고 망설여진다면, 논쟁하기 전에 실제 빌드에서 초기 HTML과 전달되는 JS를 측정하세요.

다음 단계: