핵심 요약
둘 다 React 호환이지만 사상이 다르다. Astro는 "기본 정적 + 필요한 곳만 인터랙티브 (Islands)", Next.js는 "기본 컴포넌트 = 인터랙티브 가능 + RSC로 부분 정적". 콘텐츠 vs 앱 비중에 따라 선택이 갈린다.
- Astro 5 (2026-01): React·Vue·Svelte 모두 통합, Server Islands
- Next.js 16 (2025-10): App Router 안정화, RSC 표준
- Astro 번들이 항상 작음 (인터랙티브 없으면 0KB JS)
1. 철학 차이
Astro — 기본 정적
---
// .astro 파일 — 빌드 시 한 번만 실행
const posts = await fetch('/api/posts').then(r => r.json())
---
<html>
<body>
{posts.map(p => <article>{p.title}</article>)}
<!-- 자바스크립트 0KB 페이지 -->
<!-- 필요한 곳만 island -->
<ReactCounter client:load />
</body>
</html>Next.js — 기본 컴포넌트
// page.tsx (RSC by default in Next 16)
async function PostList() {
const posts = await fetch('/api/posts').then(r => r.json())
return (
<div>
{posts.map(p => <article>{p.title}</article>)}
<ClientCounter /> {/* 클라이언트 컴포넌트 */}
</div>
)
}2. 번들 크기 비교
| 페이지 유형 | Astro | Next.js (RSC) |
|---|---|---|
| 완전 정적 콘텐츠 | 0~5KB JS | ~80KB JS |
| 일부 인터랙티브 (Counter) | ~30KB | ~120KB |
| 대시보드 (인터랙티브 많음) | ~150KB | ~180KB |
콘텐츠 사이트에서 Astro의 차이가 크다. 인터랙티브 비중이 높으면 차이 줄어듦.
3. Server Islands (Astro 5 신기능)
Astro의 정적 + dynamic 혼합. 페이지는 정적이지만 일부 영역만 동적 렌더.
---
import UserGreeting from './UserGreeting.astro'
---
<html>
<body>
<h1>블로그 — 정적</h1>
<!-- 이 부분만 요청 시점에 server에서 렌더 -->
<UserGreeting server:defer>
<p slot="fallback">Loading...</p>
</UserGreeting>
<article>블로그 콘텐츠 — 정적</article>
</body>
</html>RSC와 비슷한 개념이지만 Astro는 정적 베이스 위에 dynamic 추가, RSC는 dynamic 베이스 위에 정적 캐시.
4. 콘텐츠 통합 — Content Collections
// content/config.ts
import { defineCollection, z } from 'astro:content'
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
publishedAt: z.date(),
tags: z.array(z.string()),
}),
})
export const collections = { blog }---
// pages/blog/[slug].astro
import { getEntry } from 'astro:content'
const { slug } = Astro.params
const post = await getEntry('blog', slug)
const { Content } = await post.render()
---
<Layout title={post.data.title}>
<Content />
</Layout>Markdown·MDX 파일을 타입 안전하게 다룸. 블로그·문서 사이트에 강력.
5. 통합 — 여러 프레임워크 동시 사용
---
import ReactCounter from './Counter.tsx'
import VueChart from './Chart.vue'
import SvelteAccordion from './Accordion.svelte'
---
<!-- 동일 페이지 안에 React·Vue·Svelte 동시 -->
<ReactCounter client:load />
<VueChart client:visible />
<SvelteAccordion client:idle />레거시 코드 점진 마이그레이션·팀별 다른 프레임워크 사용 시 강함.
6. SEO·Performance
| 지표 | Astro | Next.js |
|---|---|---|
| LCP (정적 콘텐츠) | 0.6초 | 0.9초 |
| TTI (정적) | 0.7초 | 1.2초 |
| SEO (Lighthouse) | 100 | 96 |
| 접근성 | 비슷 | 비슷 |
콘텐츠 사이트에서 Astro의 LCP·TTI가 명확히 빠름. 모바일·저사양 디바이스에서 차이 더 큼.
7. 의사결정 매트릭스
| 워크로드 | 1순위 |
|---|---|
| 블로그·문서 | Astro |
| 이커머스 (콘텐츠 비중 큼) | Astro |
| 마케팅 사이트 | Astro |
| 관리자 대시보드 | Next.js |
| SaaS 앱 | Next.js |
| 실시간 협업 도구 | Next.js |
| 인터랙티브 미디어 | Next.js |
| API 위주 + 약간 페이지 | Hono/Bun (둘 다 아님) |
8. 호스팅·배포
| 플랫폼 | Astro | Next.js |
|---|---|---|
| Vercel | ★★★★ | ★★★★★ |
| Cloudflare Pages | ★★★★★ | ★★★★ |
| Netlify | ★★★★★ | ★★★★ |
| self-hosted | ★★★★★ (정적이라 단순) | ★★★★ (Node 필요) |
9. 마이그레이션
Next.js → Astro
콘텐츠 사이트라면 1~2주. 컴포넌트 대부분 그대로 사용 (.tsx → .astro 또는 island로 유지).
Astro → Next.js
인터랙션 비중 커지면 자연스러운 전환. 단 페이지 구조 재설계 필요.
실전 사례
- youngsam.net 같은 블로그+커뮤니티: Astro가 콘텐츠 부분, Next.js가 인터랙션 부분 (둘 다 사용)
- shopify storefront: Astro로 단일 사이트 마이그레이션 사례 많음
- 실시간 분석 대시보드: Next.js 압도

댓글 0