
Next.js vs React 논쟁의 프레임이 잘못되어 있습니다. Next.js는 React이고, React 위에 구축한 프레임워크일 뿐입니다. 2026년의 진정한 질문은 서버 렌더링 프레임워크의 전체 기능이 필요한지, 아니면 가볍고 간단한 Vite + React + React Router v7 SPA가 더 현명한 선택인지 하는 것입니다. 이 글에는 나란히 비교한 TypeScript 코드, 실제 성능 수치, 명확한 결론이 있으며 애매한 기능 목록만 나열하지 않습니다.
빠른 요약: Next.js vs React + Vite 한눈에 보기
Google에 노출되어야 하는 페이지가 필요하면 Next.js를 선택하세요. 서버 렌더링 HTML, 내장 이미지 최적화, 파일 기반 라우팅이 공개 웹사이트의 기본입니다.
로그인 뒤에 있는 앱이라면 React + Vite를 선택하세요. 대시보드, 관리자 패널, 내부 도구는 SSR이 필요 없으며, SPA는 빌드가 간단하고, 호스팅 비용이 저렴하고, 개발 속도가 빠릅니다.
이제 각각의 차이를 코드와 데이터로 자세히 살펴보겠습니다.
진정한 질문: 프레임워크 vs SPA
"Next.js vs React"라고 하면 마치 둘이 대안인 것처럼 들립니다. 그렇지 않습니다. 모든 Next.js 컴포넌트는 React 컴포넌트입니다. 실제 결정은 React로 빌드하는 두 가지 접근 방식 사이의 선택입니다:
- 프레임워크 방식: Next.js가 라우팅, 렌더링, 데이터 페칭, 이미지 최적화, 배포 컨벤션을 처리합니다. 많은 것을 바로 얻을 수 있지만 규칙을 따라야 합니다.
- SPA 방식: Vite를 빌드 도구로 시작하고, React Router v7(또는 타입 안전 라우팅을 위해 TanStack Router)을 추가하고, 나머지는 직접 처리합니다. 의견이 적고, 유연성이 더 높습니다.
2026년의 진정한 React SPA 스택은 어떤 모습일까
Create React App은 끝났습니다. 공식 폐기되었고, React 팀은 이제 SPA 프로젝트를 위해 Vite로 개발자를 안내합니다. 현대 SPA 스택은 다음과 같습니다:
- 빌드 도구: Vite (
npm create vite@latest my-app -- --template react-ts) - 라우팅: react-router-dom v7 또는 @tanstack/react-router
- 데이터 페칭: @tanstack/react-query (TanStack Query)
- 헤드 관리: react-helmet-async 또는 React Router의 meta 함수
프로덕션 수준의 SPA입니다. 프레임워크는 필요 없습니다.
React 팀이 실제로 말하는 것
React 문서는 프레임워크를 기본 시작점으로 권장하지만, 프레임워크의 가정에 맞지 않는 프로젝트를 위해 Vite를 권장 빌드 도구로 명시적으로 나열합니다. 미묘한 부분이 중요합니다: React의 권장사항은 "항상 Next.js를 사용하세요"가 아닙니다. "할 수 있으면 프레임워크를 사용하고, 그렇지 않을 때는 SPA를 위해 Vite를 사용하세요"입니다.
결론: 두 접근 방식 모두 React를 사용합니다. 질문은 당신의 프로젝트가 Next.js가 위에 추가하는 것을 필요로 하는지 여부입니다.
라우팅: 파일 기반 vs 명시적 설정
라우팅은 아키텍처 차이를 가장 먼저 느끼게 하는 부분입니다. Next.js는 파일 구조를 통해 라우팅을 무료로 제공합니다. Vite SPA는 라우트를 명시적으로 설정해야 합니다.
다음은 두 접근 방식에서 세 개의 라우트를 가진 간단한 앱입니다:
Next.js (App Router):
파일 구조가 라우팅 설정입니다:
app/
page.tsx // /
about/
page.tsx // /about
blog/
[slug]/
page.tsx // /blog/:slug
라우트는 파일일 뿐입니다:
export default function Home() {
return <h1>Welcome</h1>;
}
React + Vite (React Router v7):
중앙 집중식 설정에서 라우트를 정의합니다:
const router = createBrowserRouter([
{ path: "/", element: <Home /> },
{ path: "/about", element: <About /> },
{ path: "/blog/:slug", element: <BlogPost /> },
]);
export default function App() {
return <RouterProvider router={router} />;
}
트레이드오프는 간단합니다. Next.js는 파일을 만들면 라우트를 얻어 보일러플레이트를 제거합니다. 하지만 파일 기반 라우팅은 독선적입니다. 복잡한 중첩 레이아웃, 병렬 라우트, 또는 비표준 URL 패턴이 필요하면 Next.js의 컨벤션 내에서 작업해야 합니다. React Router는 완전한 제어를 주지만, 직접 설정을 작성하고 유지보수해야 합니다.
App Router가 다른 프레임워크 라우팅 시스템과 어떻게 비교되는지 자세히 알아보려면 Next.js vs Remix 비교를 참조하세요.
결론: 동점. Next.js는 표준 앱의 경우 보일러플레이트가 적습니다. React Router와 TanStack Router는 복잡한 라우팅 요구를 위해 더 많은 제어를 제공합니다. 컨벤션을 얼마나 중요하게 생각하는지에 따라 선택하세요.
데이터 페칭: 서버 vs 클라이언트
여기서 아키텍처 차이가 가장 구체적이 됩니다. Next.js는 어떤 HTML도 브라우저에 도달하기 전에 서버에서 데이터를 페칭합니다. Vite SPA는 페이지가 로드된 후 브라우저에서 데이터를 페칭합니다.
다음은 사용자 목록을 페칭하는 같은 작업을 두 접근 방식에서 보여줍니다:
Next.js (Server Component):
export default async function UserList() {
const users = await fetch("https://api.example.com/users").then(r => r.json());
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
로딩 스피너 없음. useEffect 없음. 데이터가 HTML로 도착하고, 사용자는 즉시 콘텐츠를 봅니다.
React + Vite (TanStack Query):
function UserList() {
const { data: users, isLoading } = useQuery({
queryKey: ["users"],
queryFn: () => fetch("https://api.example.com/users").then(r => r.json()),
});
if (isLoading) return <p>Loading...</p>;
return (
<ul>
{users?.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
사용자는 먼저 스피너를 본 후, API 호출이 해결되면 콘텐츠를 봅니다. TanStack Query는 캐싱, 재페칭, 오류 상태를 아름답게 처리하지만, 초기 렌더는 항상 로딩 상태입니다.
실제적인 트레이드오프: Next.js는 초기 페이지 콘텐츠에 대한 로딩 스피너를 제거하여 인지된 성능과 SEO를 개선합니다. 하지만 서버 복잡성을 추가하므로, 'use client' 지시문, 서버/클라이언트 컴포넌트 경계, 그리고 데이터가 어떻게 그들 사이를 흐르는지 이해해야 합니다. Vite SPA는 더 간단하게 이해할 수 있습니다: 모든 것이 브라우저에서 실행되고, 모든 컴포넌트가 같은 규칙을 따릅니다.
결론: Next.js는 로딩 스피너가 SEO와 사용자 경험을 해치는 공개 페이지에서 우승합니다. React + Vite는 인증된 페이지에서 우승하며, 짧은 로딩 상태는 허용되고 서버 복잡성이 정당화되지 않습니다.
SEO: 페이지 분할 결정 축
모든 비교 글에서 "Next.js가 SEO에 더 좋습니다"라고 말합니다. 맞지만 불완전합니다. 실제 질문은: 당신의 프로젝트가 SEO가 필요한가?
페이지 분할 질문
실제로 결정을 돕는 프레임워크입니다. 자신에게 물어보세요: 내 페이지의 몇 퍼센트가 Google에서 공개적으로 크롤링 가능해야 할까?
-
80% 이상 공개 페이지 (블로그, 마케팅 사이트, 전자상거래 카탈로그): Next.js가 명확한 선택입니다. SSG와 SSR은 크롤러에게 미리 렌더링된 HTML을 즉시 전달합니다. LCP는 정적으로 생성된 페이지에서 1.1-1.8초에 도달합니다. next/image 컴포넌트는 자동으로 srcset을 생성하고, 지연 로드하고, WebP로 변환합니다. Next.js의 메타데이터 export는
<title>,<meta>, Open Graph 태그를 기본 적으로 처리합니다. -
80% 이상 개인 페이지 (대시보드, 관리자 패널, 내부 도구): React + Vite SPA가 더 간단하고 충분합니다. Google은 이 페이지들을 절대 보지 않습니다. SSR은 이점을 얻지 못하는 복잡성을 추가합니다. SPA는
<div id="root">를 전달하고 JavaScript가 모든 것을 처리하며, 크롤링 가능성이 중요하지 않을 때는 괜찮습니다. -
혼합 (공개 마케팅 페이지 + 개인 앱을 가진 SaaS): Next.js가 두 가지를 모두 처리합니다. 마케팅 페이지와 랜딩 페이지를 위해 SSG를 사용하세요. 인증된 앱 부분을 위해 클라이언트 쪽 렌더링('use client')을 사용하세요. 한 코드베이스, 두 가지 렌더링 전략입니다.
SaaS 하이브리드 케이스
대부분의 SaaS 제품은 마케팅 사이트(SEO 필요)와 애플리케이션(필요 없음)을 가집니다. Next.js는 이를 우아하게 처리합니다. /pricing 페이지는 정적으로 생성되고, /app/dashboard 라우트는 클라이언트 쪽에서 렌더링됩니다. 두 개의 별도 코드베이스가 필요하지 않습니다.
대안은 분할입니다: yourproduct.com의 Next.js 마케팅 사이트와 app.yourproduct.com의 Vite SPA입니다. 일부 팀은 이러한 관심의 분리를 선호합니다. 두 접근 방식 모두 작동합니다.
네, Googlebot은 JavaScript를 실행할 수 있습니다(최신 Chrome 버전을 실행합니다). 하지만 미리 렌더링된 HTML은 인덱싱에 더 빠르고 안정적입니다. Google의 크롤러가 매번 완벽하게 작동하는 것에 베팅하고 있으며, SSG를 사용할 수 있을 때 이런 베팅을 할 필요가 없습니다.
결론: Next.js가 SEO에서 우승합니다. 하지만 당신의 페이지 중 제로가 Google 인덱싱을 필요로 한다면, 이 이점은 당신의 결정과 무관합니다. 페이지 분할 질문이 SEO가 당신의 결정에 실제로 영향을 미쳐야 하는지를 결정하는 가장 빠른 방법입니다.
성능 벤치마크: 실제 수치
"Next.js가 더 빠르다"와 같은 모호한 주장은 도움이 되지 않습니다. 다음은 두 접근 방식을 비교하는 실제 수치입니다:
| 메트릭 | Next.js SSG | React + Vite SPA |
|---|---|---|
| 초기 페이지 로드 (FCP) | 800ms | 1,200ms |
| 최대 콘텐츠 페인트 (LCP) | 1.2s | 2.1s |
| 번들 크기 | 92KB | 42KB |
| 런타임 성능 | 58fps | 60fps |
| 개발 HMR 속도 | 150ms | 45ms |
이것은 프로덕션 애플리케이션의 벤치마크 데이터를 기반으로 한 전형적인 범위입니다. 실제 수치는 앱의 복잡성, 최적화 노력, 호스팅 설정에 따라 다릅니다.
패턴은 명확합니다: Next.js는 SSG가 미리 렌더링된 HTML을 전달하기 때문에 공개 페이지의 초기 페이지 로드에서 우승합니다. 브라우저는 콘텐츠를 표시하기 전에 JavaScript를 실행할 때까지 기다리지 않습니다. 하지만 React + Vite는 번들 크기와 개발자 경험에서 우승합니다. 42KB vs 92KB 런타임은 브라우저가 파싱해야 할 JavaScript가 적다는 의미이고, Vite의 50ms 미만 HMR은 개발을 눈에 띄게 더 빠르게 만듭니다.
...