2026년 Next.js vs Remix vs Astro vs SvelteKit: 확실한 프레임워크 선택 가이드
2026년에 메타 프레임워크를 고르는 건 냉전 시대 진영 선택 같아요. 인터넷은 "Next.js는 비대하다", "Remix는 죽었다", "Astro는 블로그용이다", "SvelteKit은 프로덕션에 쓰기엔 너무 마이너하다"로 도배되어 있죠. 전부 틀린 말인데, 각 진영의 아이덴티티처럼 굳어버렸습니다.
실제로 지난 1년간 무슨 일이 있었는지 정리해볼게요. 2026년 1월에 Cloudflare가 Astro를 인수하면서 판이 바뀌었고요. Next.js는 15에서 16으로 넘어가면서 Turbopack을 프로덕션 빌드까지 안정화하고 Partial Prerendering을 정식화 방향으로 끌어올렸어요. Remix는 React Router v7에 합류하면서 동시에 Remix 3를 번들러 없는 차세대 프레임워크로 재설계 중이고, SvelteKit은 Svelte 5 runes 시스템과 함께 엔터프라이즈 시장을 뚫기 시작했습니다.
상황이 단순해진 건 아니에요. 전문화된 거죠. 근데 이게 오히려 좋은 소식입니다 — 내 프로젝트에 진짜 맞는 답이 존재한다는 뜻이니까요. 기준만 알면 됩니다.
이 글에서는 아키텍처, 렌더링 전략, 성능, 개발 경험, 생태계 성숙도, 배포까지 전부 다룹니다. 특정 프레임워크 편들기 없이, 솔직한 기술 분석만 해요.
아키텍처부터 짚고 가기
기능 비교에 앞서, 이 프레임워크들의 근본적인 차이부터 짚어야 해요. 최적화 대상에 따라 두 부류로 나뉘거든요.
앱 프레임워크 (Next.js, Remix, SvelteKit)
이 셋은 인터랙티브 웹 애플리케이션을 위해 만들어졌어요. 폼, 인증, 실시간 업데이트, 복잡한 클라이언트 상태가 있는 페이지를 전제로 설계됐죠. 모든 페이지에 런타임 JS가 필요할 수 있고, 핵심은 얼마나, 언제 보내느냐입니다.
콘텐츠 프레임워크 (Astro)
Astro는 아예 다른 문제를 풀어요. 콘텐츠 중심 웹사이트 — 대부분의 페이지가 정적 HTML인 곳이죠. JS가 기본값이 아니라 옵트인이에요. 대부분의 페이지에는 인터랙션이 필요 없고, 필요한 곳만 독립적인 "아일랜드"로 처리합니다.
좋다 나쁘다의 문제가 아니라 설계 철학 자체가 다른 거예요. Astro로 SaaS 대시보드를 만드는 건 드라이버로 못 박는 격이에요 — 되긴 하는데 도구랑 싸우는 거죠. 반대로 Next.js로 문서 사이트를 만들면 쓸데없는 JS를 잔뜩 보내게 됩니다.
첫 번째 질문은 "어떤 프레임워크가 제일 좋아?"가 아니에요. "나는 뭘 만들고 있지?"가 맞아요.
Next.js 15 → 16: 현재의 왕
Next.js는 시장 점유율, 커뮤니티, 그리고 논쟁 모두에서 1등인 React 메타 프레임워크입니다. Next.js 15가 2024년 10월에, 16이 2025년 10월에 나왔어요. 2026년 2월 현재, 가장 안전한 선택이자 가장 호불호가 갈리는 선택이기도 하죠.
2025-2026년에 뭐가 바뀌었나
Next.js 15 → 16 사이클의 주요 변화:
- Partial Prerendering (PPR): 정적 셸을 즉시 보내고, 동적 콘텐츠를 스트리밍합니다. Next.js 14에서 실험적으로 도입됐고 15에서도 실험 상태였는데, 16에서 "Cache Components" 이니셔티브의 일부로 정식화 방향으로 가고 있어요. SSG 속도에 SSR 유연성을 합친 컨셉은 강력하지만, 아직 성숙 과정입니다.
- React Compiler (안정화): 자동 메모이제이션.
useMemo,useCallback,React.memo를 직접 안 써도 컴파일러가 처리해요. - Turbopack (프로덕션까지 안정화): Next.js 15에서 개발용 안정화(2024.10) → 15.3에서 프로덕션 알파 → 15.4에서 베타 → 15.5에서 옵트인 프로덕션. 16에서 개발 + 프로덕션 모두 기본 번들러가 돼서 Webpack을 완전히 대체했어요.
- Server Actions (안정화): API 라우트 없이 클라이언트 → 서버 뮤테이션을 RPC 스타일로 처리해요.
아키텍처 깊이 보기
Next.js의 렌더링 모델은 넷 중 가장 복잡합니다:
요청 → Middleware → Route Handler
↓
┌─── 정적 셸 (엣지 캐시)
│ ↓
│ 동적 구멍 (서버에서 스트리밍)
│ ↓
└──→ 완성 HTML + RSC 페이로드 → 클라이언트 하이드레이션
사용 가능한 렌더링 모드:
- SSG — 빌드 타임 HTML
- SSR — 요청 타임 HTML
- ISR — 시간 기반 재검증 SSG
- PPR — 정적 셸 + 동적 구멍 (정식화 진행 중)
- CSR — SPA 스타일 렌더링
이 유연성이 Next.js의 최대 강점이면서 동시에 최대 혼란 원인이기도 해요. 개발자들이 자주 헤매는 부분:
- 캐싱 동작 — App Router의 캐싱이 다중 레이어(Router Cache, Full Route Cache, Data Cache, Request Memoization)라 직관적이지가 않거든요.
- 서버/클라이언트 경계 —
'use client'디렉티브를 어디에 넣을지, 직렬화 제약은 뭔지 감 잡기가 어려워요. - 멘탈 모델 부담 — 렌더링 전략이 5개면 트레이드오프도 5세트라는 뜻이죠.
코드 예시: 데이터 페칭
// app/dashboard/page.tsx — 서버 컴포넌트 (기본값) import { Suspense } from 'react'; import { RevenueChart } from './revenue-chart'; import { LatestInvoices } from './latest-invoices'; export default async function DashboardPage() { // 서버에서 실행, useEffect 불필요 const stats = await fetchDashboardStats(); return ( <div> <h1>Dashboard</h1> <StatsCards data={stats} /> {/* 동적 콘텐츠를 독립적으로 스트리밍 */} <Suspense fallback={<ChartSkeleton />}> <RevenueChart /> </Suspense> <Suspense fallback={<InvoicesSkeleton />}> <LatestInvoices /> </Suspense> </div> ); }
// app/dashboard/revenue-chart.tsx — 역시 서버 컴포넌트 export async function RevenueChart() { // 각 Suspense 경계가 독립적으로 해결 const revenue = await fetchRevenueData(); return <Chart data={revenue} />; }
Suspense 경계 덕에 정적 부분은 바로 도착하고, 무거운 데이터 페칭은 각자 독립적으로 해결됩니다.
Next.js를 고르면 좋은 경우
- 이미 React 생태계에 있고 가장 성숙한 메타 프레임워크를 원할 때
- 렌더링 유연성이 최대한 필요할 때 — SSG, SSR, ISR, PPR, CSR 전부 한 프로젝트에서
- 채용이 중요할 때 — Next.js 인력 풀이 메타 프레임워크 중 가장 커요
- 엔터프라이즈 안정성이 필요할 때 — Vercel 투자와 React 팀 협업이 장기 안정성을 보장해요
Next.js를 피해야 하는 경우
- 팀이 복잡성에 약할 때. App Router의 멘탈 모델이 가파라요. RSC 경계, 캐싱 레이어, 스트리밍에 팀이 혼란스러워하면 DX가 떨어져요.
- 콘텐츠 사이트를 만들 때. 자바스크립트를 너무 많이 보내요. Astro가 훨씬 빠를 거예요.
- Vercel 종속이 걱정될 때. 어디서든 배포 가능하지만, Vercel 전용 기능(Middleware, Edge, ISR)이 Vercel에서 제일 잘 돌아가요.
Remix: 웹 표준 순수주의자
Remix는 좀 독특한 길을 갔어요. Remix v3로 나올 예정이었던 것이 React Router v7이라는 이름으로 2024년 11월에 출시됐거든요. React Router v7을 프레임워크 모드로 쓰고 있다면, 사실상 Remix를 쓰고 있는 겁니다. 처음엔 혼란스러웠지만 전략적으로는 신의 한 수였어요 — React Router가 React 생태계에서 가장 널리 쓰이는 라우팅 라이브러리니까요.
한편 원래 Remix 팀은 Remix 3를 별도 실험 프로젝트로 진행 중인데, "배터리 포함, 의존성 제로, 번들러 불필요"를 표방하며 React 너머의 대안까지 탐색하고 있어요. 아직 초기 단계이지만, Remix 철학이 "React 프레임워크" 그 이상으로 진화 중이라는 신호죠.
핵심 철학: 웹 플랫폼을 껴안자
Remix의 핵심 믿음은 단순합니다. 웹 플랫폼이 이미 대부분의 문제를 풀었다는 거죠. 폼? <form> 쓰면 됩니다. 데이터 로딩? 서버에서 도는 loader면 충분해요. 뮤테이션? action이면 되고요. 캐싱? HTTP 캐시 헤더가 있잖아요.
Remix 앱의 특징:
- 더 탄탄합니다 — 프로그레시브 인핸스먼트 덕에 JS 없이도 핵심 기능이 돌아가거든요.
- 추론하기 쉬워요 — 클라이언트 캐시 무효화? 복잡한 재검증? 다 필요 없어요.
- HTTP에 가까워요 — Remix를 이해하면 웹 자체를 이해하게 되는 구조죠.
아키텍처 깊이 보기
Remix의 데이터 모델은 이 프레임워크들 중 독특해요:
브라우저 요청
↓
라우트 매칭 (중첩 라우트)
↓
┌─── Loader (GET) → 렌더링용 데이터 반환
│ 또는
└─── Action (POST/PUT/DELETE) → 뮤테이션 처리, loader 재검증
↓
서버가 로드된 데이터로 HTML 렌더링
↓
클라이언트 하이드레이션 + 이후 네비게이션은 SPA로 처리
핵심 개념:
- 중첩 라우트와 병렬 데이터 로딩: 각 라우트 세그먼트가 자체 loader를 가져요. 네비게이션 시 Remix가 모든 pending loader를 병렬로 가져와요 — 전통 SSR처럼 순차적이지 않아요.
- 자동 재검증: action(뮤테이션) 후에 Remix가 현재 페이지의 모든 loader를 자동으로 다시 실행해요. 캐시 무효화 로직이 필요 없어요.
- 라우트별 에러 바운더리: 각 라우트 세그먼트가 자체 에러 바운더리를 가질 수 있어서, 한 섹션의 에러가 전체 페이지를 깨뜨리지 않아요.
코드 예시: 풀 CRUD
// app/routes/invoices.tsx import type { LoaderFunctionArgs, ActionFunctionArgs } from 'react-router'; import { useLoaderData, Form } from 'react-router'; export async function loader({ request }: LoaderFunctionArgs) { const url = new URL(request.url); const query = url.searchParams.get('q') || ''; const invoices = await db.invoice.findMany({ where: { title: { contains: query } }, }); return { invoices, query }; } export async function action({ request }: ActionFunctionArgs) { const formData = await request.formData(); const intent = formData.get('intent'); if (intent === 'delete') { await db.invoice.delete({ where: { id: formData.get('id') as string }, }); } if (intent === 'create') { await db.invoice.create({ data: { title: formData.get('title') as string, amount: Number(formData.get('amount')), }, }); } // action 후 Remix가 loader를 자동으로 다시 돌림 return null; } export default function Invoices() { const { invoices, query } = useLoaderData<typeof loader>(); return ( <div> {/* 자바스크립트 없이도 동작하는 검색 */} <Form method="get"> <input name="q" defaultValue={query} placeholder="검색..." /> </Form> {invoices.map((invoice) => ( <div key={invoice.id}> <span>{invoice.title} — ${invoice.amount}</span> <Form method="post"> <input type="hidden" name="id" value={invoice.id} /> <button name="intent" value="delete">삭제</button> </Form> </div> ))} <Form method="post"> <input name="title" placeholder="제목" required /> <input name="amount" type="number" placeholder="금액" required /> <button name="intent" value="create">추가</button> </Form> </div> ); }
useState도 없고, useEffect도 없고, fetch 호출도 없고, 로딩 상태도 직접 관리 안 해요. 데이터 흐름이 요청 → loader → 렌더 → action → 재검증으로 깔끔해요.
Remix를 고르면 좋은 경우
- 웹 표준과 점진적 향상을 중시할 때. Remix 앱은 자바스크립트 없이도 기본 기능이 돌아가요.
- 폼 중심 앱 (SaaS 어드민, 대시보드, CRUD 집약 도구)을 만들 때
- 간단한 멘탈 모델을 원할 때. 캐싱 레이어 디버깅도, RSC 경계 관리도 안 해도 돼요.
- React Router를 이미 쓰고 있을 때. React Router v7에서 Remix로의 전환은 설정 하나 바꾸는 수준이에요.
Remix를 피해야 하는 경우
- 정적 사이트 생성이 필요할 때. Remix는 서버 우선이라 빌드 타임 SSG가 없어요.
- 최대 생태계 지원이 필요할 때. React Router v7 합병이 커뮤니티 분열을 어느 정도 야기했어요. 일부 패키지가 아직 업데이트 안 됐고요.
- ISR이나 PPR이 필요할 때. HTTP 헤더로 캐싱을 직접 제어해야 해요 (강력하지만 수동 작업이 더 필요해요).
Astro: 성능 혁명 (이젠 Cloudflare 품)
Astro의 2026년은 한 줄로 요약됩니다: Cloudflare가 2026년 1월에 Astro를 인수했어요. 단순한 투자가 아닌 근본적 변화죠. Astro가 Cloudflare 엣지 인프라에 직접 접근할 수 있게 됐고, 통합은 이미 나오고 있어요.
아일랜드 아키텍처
Astro의 핵심 혁신은 급진적일 만큼 단순해요: 기본적으로 JS 0KB.
전통 SPA:
[자바스크립트 셸] → [전체 하이드레이션] → [인터랙티브]
~200-500KB JS 최소
Astro:
[정적 HTML] → [인터랙티브 아일랜드가 독립적으로 하이드레이션]
~0KB JS 기본 + 아일랜드가 필요한 만큼만
모든 Astro 페이지는 기본이 정적 HTML이에요. 인터랙션이 필요하면 "아일랜드"를 만들어요 — 독립적으로 하이드레이션되는 격리된 컴포넌트요. 하이드레이션 타이밍도 제어할 수 있어요:
--- // src/pages/blog/[slug].astro import BaseLayout from '../../layouts/BaseLayout.astro'; import TableOfContents from '../../components/TableOfContents.tsx'; import CommentsSection from '../../components/CommentsSection.tsx'; import ShareButtons from '../../components/ShareButtons.svelte'; import { getEntry } from 'astro:content'; const { slug } = Astro.params; const post = await getEntry('blog', slug); const { Content } = await post.render(); --- <BaseLayout title={post.data.title}> <article> <h1>{post.data.title}</h1> <!-- 즉시 하이드레이션 — 스크롤 추적에 필요 --> <TableOfContents client:load /> <!-- 정적 HTML — 본문에는 JS가 필요 없어요 --> <Content /> <!-- 보일 때 하이드레이션 — 스크롤해야 보이니까 리소스 절약 --> <CommentsSection client:visible /> <!-- 유휴 시 하이드레이션 — 낮은 우선순위 --> <ShareButtons client:idle /> </article> </BaseLayout>
하이드레이션 디렉티브:
client:load— 페이지 로드 시 즉시 하이드레이션client:idle— 브라우저가 유휴 상태일 때client:visible— 컴포넌트가 뷰포트에 들어올 때client:media— CSS 미디어 쿼리가 매치될 때client:only— 서버 렌더링 건너뛰고 클라이언트에서만
블로그 글 본문에는 JS 0KB, 댓글 섹션은 유저가 스크롤해야 JS가 로드됩니다. 이게 Astro의 진짜 강점이에요.
Cloudflare 팩터
Astro v6(현재 베타)는 Cloudflare와 깊이 통합됩니다:
- 개발 서버가 Cloudflare 런타임에서 동작 — 개발 환경이 프로덕션과 정확히 같아요. Workers 전용 API에서 "로컬에서는 되는데 프로덕션에서 안 돼" 문제가 사라지죠.
- Cloudflare 프리미티브에 직접 접근 — Durable Objects, R2 Storage, D1 Database, AI Workers를 Astro 컴포넌트에서 바로 쓸 수 있어요.
- 글로벌 엣지 배포가 기본 — 모든 Astro 사이트가 설정 없이 Cloudflare 엣지 네트워크에 올라갑니다.
이게 왜 큰 건지 — Astro가 더 이상 "정적 사이트 프레임워크"에 머물지 않는다는 뜻이거든요. Workers, D1, Durable Objects로 진짜 동적인 앱을 만들면서도 JS 0KB 기본 철학을 유지할 수 있습니다.
프레임워크 불문: 숨겨진 무기
Astro에서 가장 과소평가된 기능이 있는데, 어떤 UI 프레임워크든 Astro 안에서 쓸 수 있다는 거예요. React, Vue, Svelte, Solid, Preact, Lit — 골라잡으세요. 섞어도 됩니다.
--- // 네, 진짜 React와 Svelte를 같은 페이지에 섞을 수 있어요 import ReactCounter from '../components/ReactCounter.tsx'; import SvelteChart from '../components/SvelteChart.svelte'; import VueForm from '../components/VueForm.vue'; --- <h1>프레임워크 샐러드</h1> <ReactCounter client:load /> <SvelteChart client:visible /> <VueForm client:idle />
과장 같지만 진짜 유용한 상황:
- 마이그레이션 — Vue에서 React로 전환 중? 전환기에 둘 다 써요.
- 최고 조합 — React 차트 라이브러리 + Svelte 폼 라이브러리를 같이 쓰는 식이에요.
- 팀 유연성 — 팀마다 다른 프레임워크를 쓸 수 있어요.
Astro를 고르면 좋은 경우
- 콘텐츠 중심 웹사이트: 블로그, 문서, 마케팅, 이커머스. Next.js보다 2-10배 빠를 거예요.
- 성능이 양보 불가일 때. Core Web Vitals 만점에 가장 쉬운 경로예요.
- Cloudflare 생태계를 원할 때. 인수 이후 최고 수준의 통합이에요.
- 프레임워크를 섞어 쓰는 팀이면. 여러 UI 프레임워크를 네이티브로 지원하는 유일한 메타 프레임워크예요.
Astro를 피해야 하는 경우
- 풀스택 SaaS. 모든 페이지에 인증, 실시간 업데이트, 복잡한 클라이언트 상태가 필요하면 아일랜드 모델이 마찰을 일으켜요. 전부
client:load달게 되죠. - SPA 스타일 네비게이션이 필요할 때. Astro는 기본이 풀페이지 네비게이션이에요 (View Transitions로 부드럽게 처리하긴 하지만). 상태 유지가 필요한 클라이언트 네비게이션이라면 React 프레임워크가 더 맞아요.
- 성숙한 React 생태계가 필요할 때. Astro가 React를 지원하긴 하지만, Astro 자체 생태계는 Next.js보다 작아요.
SvelteKit: 개발 경험의 정점
SvelteKit은 개발자 만족도 설문에서 계속 1위를 차지하는 다크호스입니다. Svelte 5의 runes 시스템 위에 만들어져 있고, 한 번 써보면 React가 장황하게 느껴질 정도의 DX를 제공하죠.
Svelte는 뭐가 다를까
Svelte는 리액티비티를 완전히 다르게 접근합니다: 프레임워크를 컴파일해서 없애버려요.
React:
소스 코드 → [React 런타임 (44KB)] → 가상 DOM 비교 → DOM 업데이트
Svelte:
소스 코드 → [컴파일러] → 수술적 DOM 업데이트 (런타임 없음, 가상 DOM 없음)
가상 DOM도 없고, 비교 알고리즘도 없어요. Svelte 컴파일러가 빌드 타임에 코드를 분석해서, 정확한 DOM 업데이트를 하는 바닐라 JS를 생성합니다. 결과는? 더 작은 번들, 더 빠른 런타임.
Svelte 5 Runes: 새로운 리액티비티
Svelte 5는 기존 $: 문법을 "runes"로 교체했어요 — 더 예측 가능하고 조합 가능한 리액티비티 프리미티브예요:
<script> // Svelte 5 runes let count = $state(0); let doubled = $derived(count * 2); function increment() { count++; // 그냥 변경 — Svelte가 추적해요 } </script> <button onclick={increment}> {count} × 2 = {doubled} </button>
React와 비교:
function Counter() { const [count, setCount] = useState(0); const doubled = useMemo(() => count * 2, [count]); return ( <button onClick={() => setCount(c => c + 1)}> {count} × 2 = {doubled} </button> ); }
Svelte 쪽이 더 짧죠. hook 규칙 외울 필요도 없고, stale closure 버그도 없고, 의존성 배열도 없습니다. 컴파일러가 리액티비티 추적을 전부 알아서 해줘요.
SvelteKit 아키텍처
SvelteKit의 아키텍처는 Remix와 여러 면에서 비슷해요 — 중첩 라우트, 서버 우선 데이터 로딩, 폼 액션:
브라우저 요청
↓
라우트 매칭 (+layout.svelte 중첩)
↓
+page.server.ts load() → 데이터 반환
↓
+page.svelte가 로드된 데이터로 렌더링
↓
클라이언트 하이드레이션 + SPA 네비게이션 처리
코드 예시: 풀스택 데이터 플로우
// src/routes/todos/+page.server.ts import type { PageServerLoad, Actions } from './$types'; export const load: PageServerLoad = async ({ locals }) => { const todos = await locals.db.todo.findMany({ where: { userId: locals.user.id }, orderBy: { createdAt: 'desc' }, }); return { todos }; }; export const actions: Actions = { create: async ({ request, locals }) => { const data = await request.formData(); await locals.db.todo.create({ data: { text: data.get('text') as string, userId: locals.user.id, }, }); }, delete: async ({ request, locals }) => { const data = await request.formData(); await locals.db.todo.delete({ where: { id: data.get('id') as string }, }); }, };
<!-- src/routes/todos/+page.svelte --> <script> import { enhance } from '$app/forms'; let { data } = $props(); </script> <h1>My Todos</h1> <form method="POST" action="?/create" use:enhance> <input name="text" placeholder="할 일을 입력하세요" required /> <button>추가</button> </form> <ul> {#each data.todos as todo} <li> {todo.text} <form method="POST" action="?/delete" use:enhance> <input type="hidden" name="id" value={todo.id} /> <button>×</button> </form> </li> {/each} </ul>
use:enhance 디렉티브가 프로그레시브 인핸스먼트를 담당합니다 — 폼이 JS 없이도 동작하면서, JS가 있으면 SvelteKit이 제출을 가로채서 SPA 같은 경험과 자동 재검증을 제공하죠.
성능: 컴파일러의 강점
SvelteKit의 컴파일된 출력은 일관되게 더 작은 번들을 만들어요:
| 프레임워크 | Hello World 번들 | 중간 규모 앱 번들 | Gzipped |
|---|---|---|---|
| Next.js 15/16 | ~85KB | ~180-250KB | ~60-80KB |
| Remix | ~65KB | ~150-220KB | ~50-70KB |
| SvelteKit | ~15KB | ~60-120KB | ~20-40KB |
| Astro (아일랜드 없이) | ~0KB | ~0-50KB | ~0-15KB |
SvelteKit은 동일 기능 기준으로 React 프레임워크보다 일관되게 50-70% 적은 JS를 보냅니다. TTI와 INP 점수에 직접 영향을 주죠.
SvelteKit을 고르면 좋은 경우
- 개발 경험이 최우선일 때. Svelte가 만족도 설문 1위를 계속 해요. Runes 시스템이 진짜 즐거워요.
- 성능이 중요한데 풀스택 프레임워크가 필요할 때. 앱 프레임워크 중 가장 작은 번들이에요.
- 스타트업을 만들 때. 작은 팀 + Svelte의 생산성 = 더 빠른 출시.
- React의 복잡성 없이 "모던" 경험을 원할 때 (hook 규칙, 의존성 배열, RSC 경계 같은 거 없이).
SvelteKit을 피해야 하는 경우
- 대규모 채용이 필요할 때. React 개발자가 Svelte 개발자보다 훨씬 많아요.
- React 생태계 패키지에 의존할 때. 컴포넌트 라이브러리, CMS 연동, 인증 솔루션 — React가 10배 더 많아요.
- 엔터프라이즈 채택 실적이 중요할 때. 성장 중이지만, Next.js보다는 짧아요.
비교 매트릭스
진짜 중요한 지표로 나란히 놓고 보기:
성능 (낮을수록 좋음)
| 지표 | Next.js 15/16 | Remix | SvelteKit | Astro |
|---|---|---|---|---|
| 평균 JS 번들 (콘텐츠 페이지) | 85-120KB | 70-100KB | 20-50KB | 0-5KB |
| 평균 JS 번들 (앱 페이지) | 180-250KB | 150-220KB | 60-120KB | N/A* |
| 콜드 스타트 (서버리스) | ~120-200ms | ~80-150ms | ~60-120ms | ~30-80ms |
| TTFB (정적) | ~20ms (CDN) | ~50-100ms | ~20ms (CDN) | ~10ms (CDN) |
| Lighthouse 점수 (콘텐츠) | 85-95 | 90-98 | 92-99 | 98-100 |
Astro는 풀 앱 페이지용이 아니라 직접 비교가 공정하지 않아요.
개발 경험
| 요소 | Next.js 15/16 | Remix | SvelteKit | Astro |
|---|---|---|---|---|
| 학습 곡선 | 가파름 (RSC, 캐싱) | 보통 (웹 표준) | 완만 (직관적) | 쉬움 (HTML+) |
| TypeScript 지원 | 훌륭 | 훌륭 | 훌륭 | 훌륭 |
| HMR 속도 (Turbopack) | 빠름 | 빠름 | 매우 빠름 | 매우 빠름 |
| 멘탈 모델 복잡도 | 높음 (5가지 모드) | 낮음 (loader/action) | 낮음 (load/actions) | 매우 낮음 (정적+) |
| 개발자 만족도 | 엇갈림 | 높음 | 최고 | 높음 |
생태계 & 커뮤니티
| 요소 | Next.js 15/16 | Remix | SvelteKit | Astro |
|---|---|---|---|---|
| npm 주간 다운로드 | ~7M | ~2M* | ~500K | ~800K |
| 컴포넌트 라이브러리 | 대량 | 대규모 (React) | 성장 중 | 통합으로 |
| 채용 시장 | 압도적 | 보통 | 성장 중 | 니치 |
| 기업 후원 | Vercel | Shopify | Vercel** | Cloudflare |
| GitHub Stars | ~130K | React Router 54K | ~82K | ~50K |
Remix 다운로드는 React Router v7 안에 포함돼요.
*Vercel이 Rich Harris(Svelte 창시자)와 Svelte 팀원 여러 명을 고용하고 있어요.
배포 & 호스팅
| 요소 | Next.js 15/16 | Remix | SvelteKit | Astro |
|---|---|---|---|---|
| 최적 배포 타겟 | Vercel | 아무 Node 호스트 | 아무 곳 (어댑터) | Cloudflare |
| 엣지 런타임 | 가능 (Vercel) | 가능 (어댑터) | 가능 (어댑터) | 네이티브 (CF Workers) |
| 셀프호스팅 용이성 | 보통 | 쉬움 | 쉬움 | 쉬움 |
| 정적 내보내기 | 가능 | 불가 | 가능 | 가능 (기본) |
| Docker 지원 | 가능 | 가능 | 가능 | 가능 |
실전 의사결정 가이드
"어떤 프레임워크가 제일 좋아?"를 멈추고 **"나는 뭘 만들고 있어?"**를 물어보세요.
콘텐츠 사이트를 만든다면? → Astro
블로그, 문서, 마케팅, 포트폴리오, 이커머스 스토어. 성능 격차가 압도적이에요. Cloudflare 인수까지 있으니 장기적으로도 안심이에요.
풀스택 웹 앱을 만든다면? → Next.js 또는 SvelteKit
SaaS, 어드민, SNS, 복잡한 인터랙션의 마켓플레이스.
- Next.js: 대규모 채용이 중요하거나 React 생태계에 이미 투자했을 때
- SvelteKit: DX를 중시하고, 팀이 중소규모이고, 성능이 중요할 때
폼 중심 CRUD 앱을 만든다면? → Remix
내부 툴, 어드민 패널, 다단계 워크플로우. Remix의 loader/action 패턴이 정확히 이런 용도로 만들어졌어요. 프로그레시브 인핸스먼트 덕에 폼이 JS 없이도 돌아가요.
잘 모르겠다면? → Next.js
진짜 못 정하겠고 미래가 불확실하면, Next.js가 가장 안전한 배팅이에요. 커뮤니티, 패키지, 유연성 전부 가장 커요. 어떤 하나에서 최고는 아니지만, 전부에서 괜찮아요.
아무도 안 말하는 숨겨진 변수들
1. 배포 종속 스펙트럼
- 가장 이식성 좋음: Remix, SvelteKit — 어댑터 시스템으로 어디서든 최소 변경으로 배포
- 약간 종속: Astro — 어디서든 되지만 Cloudflare가 확실히 일급 경험
- 가장 종속적: Next.js — 기술적으로 어디서든 배포 가능하지만 ISR, Middleware, Image Optimization, PPR이 Vercel에서 가장 잘(혹은 Vercel에서만) 동작. 셀프호스팅에는 상당한 운영 지식이 필요해요.
2. TypeScript 경험 차이
넷 다 TypeScript를 지원하지만 품질은 달라요:
- Next.js: 좋지만 가끔 답답해요. 서버/클라이언트 컴포넌트 경계가 타입 시스템을 혼란시킬 수 있어요.
generateStaticParams,generateMetadata같은 컨벤션은 Next.js만의 방식을 따로 배워야 하고요. - Remix: 훌륭해요.
useLoaderData<typeof loader>()가 서버 → 클라이언트 타입 추론을 완벽하게 해줘요. - SvelteKit: 훌륭해요.
$types자동 생성이 마법 같아요 —+page.server.ts에서+page.svelte로 타입이 매끄럽게 흘러요. - Astro: 콘텐츠에 훌륭해요. Content Collections가 프론트매터의 타입 안전 검증을 해줘요.
3. 팀 규모별 추천
- 혼자 / 1-3명: SvelteKit이나 Astro. 최대 생산성, 최소 세레모니.
- 소규모 (4-10명): SvelteKit이나 Remix. 빠른 반복, 심플한 멘탈 모델.
- 중규모 (10-30명): Next.js나 SvelteKit. Next.js의 컨벤션이 규모에서 일관성을 잡아줘요.
- 대규모 (30+명): Next.js. 채용 풀의 이점이 결정적이에요.
4. "리라이트 리스크"
프레임워크는 진화해요. 업그레이드가 얼마나 파괴적인지?
- Next.js — 큰 API 변경 이력이 있어요 (Pages → App Router 마이그레이션은 고통스러웠음). React 생태계의 변화 속도(RSC, Compiler, Server Actions)가 빨라서 계속 공부해야 해요.
- Remix — React Router v7 합병이 혼란스러웠지만 기술적으로 크게 깨지진 않았어요.
- SvelteKit — Svelte 4 → 5 (runes)가 가장 큰 변화였어요. 마이그레이션 도구가 좋았지만 패러다임 전환이었죠.
- Astro — API 변화가 가장 적었어요. Cloudflare 인수는 기존 API를 깨지 않고 기능을 추가했어요.
앞으로의 전망
메타 프레임워크들이 흥미로운 방향으로 수렴하고 있습니다.
Next.js 16은 PPR을 기본 렌더링 모드로 안정화하는 중이에요. Turbopack 전환은 끝났고 — Webpack은 사실상 레거시. React Compiler가 성숙하면서 SvelteKit과의 DX 격차도 좁아질 겁니다.
Remix/React Router는 두 갈래로 나뉘는 중이에요. React Router v7이 안정적인 프로덕션 프레임워크로, Remix 3가 차세대 웹 개발 실험장으로. Shopify 후원 아래 "실용적" 선택으로 자리잡는 중이죠.
Astro는 Cloudflare 아래에서 가장 흥미로운 궤적을 그리고 있어요. Workers AI, Durable Objects, R2와의 더 깊은 통합이 예상됩니다. "최고의 정적 사이트 프레임워크"에서 "최고의 Cloudflare 프레임워크"로 진화하는 건 시간문제일 수 있어요.
SvelteKit은 Svelte 5의 성숙과 엔터프라이즈 채택 확대의 수혜를 받을 겁니다. 컴파일러 접근이 성능을 위한 올바른 베팅이었다는 게 점점 입증되고 있거든요. Rich Harris가 Vercel에 있으니 리소스도 보장돼요.
솔직한 진실: 프레임워크들 사이의 기능 격차가 좁아지고 있습니다. 남아있는 차이는 기능적이라기보다 철학적이에요(JS 0KB 기본 vs 전부 하이드레이트, 웹 표준 vs 추상화). 2년 후에는 "잘못된" 선택의 임팩트가 지금보다 훨씬 작아질 거예요.
결론
"어떤 메타 프레임워크를 써야 해?"의 진짜 답은 세 부분이에요:
1. 콘텐츠 유형에 맞춰:
- 콘텐츠 중심 → Astro
- 앱 중심 → Next.js, SvelteKit, 또는 Remix
2. 팀에 맞춰:
- 대규모 React 팀 → Next.js
- 생산성 원하는 소규모 팀 → SvelteKit
- 웹 표준 중시하는 팀 → Remix
- 프레임워크를 섞어 쓰는 팀 → Astro
3. 배포 타겟에 맞춰:
- Cloudflare → Astro
- Vercel → Next.js나 SvelteKit
- 어디서든/셀프호스팅 → Remix나 SvelteKit
메타 프레임워크 전쟁은 사실 전쟁이 아닙니다. 전문화예요. 각각이 프로젝트 유형 × 팀 구성 × 배포 타겟의 특정 조합에서 최선의 선택이죠. 내 제약 조건만 파악하면 답은 뻔해집니다.
프레임워크 논쟁은 그만하고 프로덕트 출시하세요.
관련 도구 둘러보기
Pockit의 무료 개발자 도구를 사용해 보세요