반응형

 

Next.js를 처음 시작하거나 기존 프로젝트를 마이그레이션 하려는 분들이 가장 먼저 마주치는 난관은 바로 라우터 선택입니다. App Router가 최신이라는 사실만 아시는 분들이 많을 것입니다. 최신이라고 무조건 써야 하나 고민이 많으신 분들이 많을 겁니다.

 

결론부터 말씀드리면, App Router는 단순한 업데이트가 아닙니다. React를 사용하는 방식 자체를 바꾼 '새로운 프레임워크'에 가깝습니다. 이번 글에서는 Page Router와 App Router의 핵심 차이를 상세히 살펴보겠습니다.

1. 렌더링 방식의 변화 (Client vs Server First)

가장 큰 차이점은 기본 렌더링 전략입니다.

Pages Router: Client-Side 중심

기존 Page Router에서는 모든 컴포넌트가 기본적으로 Client Component처럼 동작했습니다. 서버에서 HTML을 미리 만들어주긴 하지만(SSR/SSG), 브라우저에 도착하면 다시 자바스크립트가 실행되어야 했습니다.(Hydration)

App Router: Server Component (RSC) 중심

App Router의 모든 컴포넌트는 기본적으로 Server Component입니다. 이는 브라우저가 자바스크립트를 다운로드하고 실행할 필요 없이, 서버에서 이미 완성된 HTML을 받아오기만 하면 된다는뜻입니다.

  • JS 번들 사이즈가 획기적으로 줄어듭니다. (초기 로딩 속도 Up)
  • useState, useEffetct 등과 같은 훅을 쓰려면 파일 최상단에 'use client'를 선언해야 합니다.

2. 디렉터리 구조와 라우팅

파일을 어디에 두느냐에 따라 URL이 결정되는 방식도 달라졌습니다.

Pages Router

  • pages 폴더 안의 파일 이름이 곧 URL입니다.
  • pages/about.tsx → about
  • pages/blog/[slug].tsx → /bolg/1

App Router

  • app 폴더 안의 폴더 이름이 URL 세그먼트가 되고, 그 안의 page.tsx 파일이 렌더링 됩니다.
  • app/about/page.tsx → /about
  • app/blog/[slug]/page.tsx → /blog/1

 

단순하게 페이지만 보여주는 것이 아니라 layout.tsx, loading.tsx, error.tsx 등 특수 파일들을 같은 폴더(URL) 안에 묶어서 관리하기 위함입니다. 이를 통해 관련된 코드를 한 곳에 두는 것(Colocation)이 가능해졌습니다.

3. 데이터 페칭

개발자 입장에서 가장 체감이 큰 변화입니다. 복잡했던 getStaticProps, getServerSideProps 가 사라졌습니다.

Pages Router

Next.js만의 전용 함수를 따로 export 해야 했습니다. 데이터 흐름이 컴포넌트와 분리되어 있어 직관적이지 않았죠.

// pages/products.tsx
export async function getServerSideProps() {
  const res = await fetch('https://api.example.com/products');
  const data = await res.json();
  return { props: { data } };
}

export default function Products({ data }) {
  return <div>{data.name}</div>;
}

App Router

표준 Web Fetch API와 async/await를 컴포넌트 내부에서 직접 사용합니다. 훨씬 직관적입니다.

// app/products/page.tsx
async function getProducts() {
  const res = await fetch('https://api.example.com/products');
  return res.json();
}

export default async function Products() {
  // 컴포넌트 안에서 바로 데이터를 가져옵니다!
  const data = await getProducts();
  return <div>{data.name}</div>;
}

4. 레이아웃

대시보드 같은 복잡한 UI를 만들 때 App Router의 진가가 발휘됩니다.

Pages Router

공통 레이아웃을 잡으려면 _app.tsx라는 최상위 파일에서 모든 처리를 하거나, 복잡한 패턴을 써야 했습니다. 페이지가 바뀔 때 레이아웃이 불필요하게 리렌더링 되는 문제가 잦았습니다.

App Router

중첩 레이아웃을 지원합니다.

  • app/dashboard/layout.tsx: 대시보드 전체 레이아웃
  • app/dashboard/settings/layout.tsx: 설정페이지 내부만의 레이아웃

 

URL이 바뀌어도 상위 레이아웃은 그대로 유지되고, 하위 내용만 갈아 끼워집니다. SPA처럼 부드러운 사용자 경험을 제공합니다.

메타데이터 (SEO)

Next.js를 사용하는 가장 큰 이유 중에 하나인 SEO도 두 라우터 모두 강력하게 지원하지만, 메타 태그를 어디서, 어떻게 정의하는지 살짝 차이가 있습니다.

Pages Router

Next.js에서 제공하는 <Head> 컴포넌트를 import 해서, 각 페이지 파일(index.tsx) 내부의 JSX 안에 직접 태그를 작성해야 했습니다.

// pages/index.tsx
import Head from 'next/head';

export default function Page() {
  return (
    <>
      <Head>
        <title>코딩병원 블로그</title>
        <meta name="description" content="설명..." />
      </Head>
      <div>페이지 내용</div>
    </>
  );
}

App Router

반면 App Router는 Metadata API라는 표준화 방식을 사용합니다. 더 이상 JSX 안에 <Head>를 숨기지 않고, layout.tsx나 page.tsx파일에서 metadata라는 객체(+함수)를 export 하기만 하면 Next.js가 알아서 HTML 헤더를 완성해 줍니다.

// app/page.tsx
import type { Metadata } from 'next';

// 정적 메타데이터
export const metadata: Metadata = {
  title: '코딩병원 블로그',
  description: 'Next.js 14 완벽 가이드',
};

export default function Page() { ... }

 

이미 운영 중인 프로젝트가 거대하지 않다면, 무조건 App Router를 추천합니다.

 

물론, 최근에 Next.js 관련 보안 이슈가 터지며 우려의 목소리가 있었던 것은 사실입니다. 하지만 이는 모든 혁신적인 신기술 주류로 자리 잡는 과정에서 겪는 필연적인 성장통과도 같습니다. 다행히 Vercel 팀과 오픈소스 커뮤니티는 그 어떤 생태계보다 빠르고 투명하게 문제를 해결하며 성숙해지고 있습니다.

 

당장의 러닝커브나 마이그레이션의 귀찮음 때문에 주저하기엔, App Router가 제공하는 압도적인 초기 로딩 속도직관적인 데이터 관리 경험이 주는 이점이 너무나 큽니다. 따라서 저는 두 라우터 중에 App Router를 강력 추천합니다!

 

 

References

https://nextjs.org/docs/app/guides/migrating/app-router-migration

[Next.js] RSC의 역습? CVE-2025-55182 원격 코드 실행(RCE) 취약점 분석

https://nextjs.org/docs/app/getting-started/server-and-client-components

 

 

반응형