[Nextjs] AppRoute와 PageRoute 비교

Arin·2025년 3월 4일

Nextjs

목록 보기
2/2
post-thumbnail

Next.js 13부터 App Router(app/ 디렉토리)가 등장하면서 기존 Pages Router(pages/ 디렉토리) 방식과 큰 차이가 생겼습니다. 아래 표는 두 방식을 간략하게 비교한 표 입니다.

🚀 주요 차이점🏗 Pages Router (기존)🌟 App Router (Next.js 13+)
디렉토리 구조pages/ 사용app/ 사용
라우팅 방식파일 기반 (예: pages/index.tsx)폴더 + page.tsx 사용 (예: app/page.tsx)
데이터 패칭getServerSideProps, getStaticPropsfetch() 자동 캐싱 및 useEffect, useState 사용
서버/클라이언트 분리모든 컴포넌트가 클라이언트 컴포넌트기본적으로 Server Component (필요 시 "use client")
SSR 지원 방식getServerSideProps 사용기본적으로 서버 렌더링 지원 (자동)
글로벌 상태 관리Provider를 _app.tsx에서 설정Provider를 layout.tsx에서 설정
라우트 그룹핑❌ 없음✅ app/(group)/page.tsx 사용 가능
Middlewaremiddleware.ts 사용✅ 동일하게 middleware.ts 지원
SEO 지원next/head 사용✅ metadata 내장 지원
React Suspense 지원❌ 제한적✅ 기본 지원 (로딩 처리 간편)

위의 내용을 좀 더 자세히 설명해 보겠습니다.

1. 서버 중심(SERVER-FIRST) 렌더링 최적화

✅ 기존 Pages Router의 문제점

기존 Pages Router에서는 모든 컴포넌트가 기본적으로 클라이언트에서 렌더링 되었습니다. SSR을 사용하려면 getServerSideProps, getStaticProps, getInitialProps 같은 API를 따로 사용해야 했고, 이것들이 혼합되면 복잡해졌죠.

✅ App Router의 개선점

App Router에서는 기본적으로 모든 컴포넌트가 서버 컴포넌트(Server Component)로 동작합니다. 서버에서 데이터를 처리하고, 필요한 부분만 클라이언트에서 실행할 수 있습니다.

// ✅ App Router 방식 (서버에서 실행됨)
export default async function Page() {
  const data = await fetch("https://api.example.com/data");
  const json = await data.json();

  return <div>{json.message}</div>;
}

📌 → 클라이언트로 불필요한 데이터 전달을 줄여 성능 최적화
📌 → 서버에서 데이터 가져오는 코드 정리(getServerSideProps 필요 없음)

2. React Server Component(RSC) 지원

✅ 기존 Pages Router의 문제점

기존 Next.js에서는 모든 컴포넌트가 클라이언트에서 실행돼야 했습니다. 그래서 SSR을 할 때도 클라이언트에서 불필요한 코드가 로드되는 경우가 많았습니다.

✅ App Router의 개선점

React Server Component(RSC)를 활용해서 클라이언트에서 실행할 필요 없는 로직을 서버에서 처리 가능합니다.
필요한 곳에만 "use client"를 추가해서 클라이언트 컴포넌트로 만들 수 있습니다.

// 🚀 서버 컴포넌트 (기본값)
export default async function ServerComponent() {
  const data = await fetch("https://api.example.com/data");
  return <div>{data.message}</div>;
}
// 🚀 클라이언트 컴포넌트 (use client 추가 필요)
"use client";
import { useState } from "react";

export default function ClientComponent() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}

📌 → 클라이언트 컴포넌트는 UI/상태 관리, 서버 컴포넌트는 데이터 로딩 담당
📌 → 서버 컴포넌트는 무거운 연산도 서버에서 처리 가능

3. Suspense 기반의 스트리밍(Streaming) 지원

✅ 기존 Pages Router의 문제점

기존에는 getServerSideProps를 사용할 때 모든 데이터가 준비될 때까지 화면이 비어있는 문제가 있었습니다.

✅ App Router의 개선점

App Router는 React Suspense를 기본 지원해서, 데이터가 준비된 부분부터 점진적으로 화면을 렌더링할 수 있습니다.

// 🚀 Suspense를 활용한 코드 예제
import { Suspense } from "react";
import SlowComponent from "./SlowComponent";

export default function Page() {
  return (
    <div>
      <h1>페이지 로딩 중...</h1>
      <Suspense fallback={<p>로딩 중...</p>}>
        <SlowComponent />
      </Suspense>
    </div>
  );
}

📌 → 일부 데이터가 늦게 오더라도 페이지 전체가 멈추지 않음
📌 → 유저 경험(UX) 개선

4. 폴더 기반의 구조적 라우팅

✅ 기존 Pages Router의 문제점

pages/는 파일명 기반 라우팅이라 그룹핑이 어려웠습니다. API 라우트와 페이지 라우트가 같은 pages/ 안에 섞여 있어 관리하기 불편했습니다.

✅ App Router의 개선점

폴더 기반 라우팅으로 더 직관적인 구조를 만들 수 있습니다. 레이아웃(layout.tsx) 단위로 공통 UI를 구성할 수 있습니다.

📂 App Router 방식
app/
 ├── layout.tsx  # 공통 레이아웃
 ├── page.tsx    # /
 ├── about/
 │   ├── page.tsx  # /about
 ├── dashboard/
 │   ├── layout.tsx  # 대시보드 공통 레이아웃
 │   ├── page.tsx    # /dashboard
 │   ├── settings/
 │   │   ├── page.tsx  # /dashboard/settings

📌 → 공통 레이아웃을 layout.tsx에서 관리 가능
📌 → app/을 이용해 기능별로 폴더를 정리할 수 있음

5.Middleware와 API 경로 분리

✅ 기존 Pages Router의 문제점

API 라우트(/pages/api/*)와 프론트엔드 코드가 같은 pages/ 폴더에 있어서 관리가 불편했습니다.

✅ App Router의 개선점

app/api/* 폴더를 따로 제공해서 API 경로를 분리할 수 있습니다.
Middleware(middleware.ts)도 그대로 지원해서 보안/인증 기능을 간편하게 추가 가능합니다.

// app/api/hello/route.ts
export async function GET() {
  return Response.json({ message: "Hello from API!" });
}

AppRoute 개발 이유

전반적으로 비교를 해보니 AppRoute 방식을 만든 의도가 보이네요. 핵심 컨셉에 맞게 SSR기능을 좀더 효율적으로 사용할 수 있도록 만들었다는 생각이 듭니다.

profile
기록을 습관화 해야 한다.

0개의 댓글