Full-Stack Developer at AI FinTech Compa

Pages Router에서 App Router로 변화한 이유 본문

Front-end

Pages Router에서 App Router로 변화한 이유

youkn0wthat 2026. 5. 28. 01:47
반응형

 

페이지 라우터를 사용하지 않고, 왜 앱 라우터를 사용하셨나요? > 최신 기술이라서요.

 


기존 Pages Router의 한계

Pages Router는 오랫동안 (2016년 ~ 2022년)  안정적으로 사용되어 온 라우팅 방식

 

pages 디렉터리 안에 파일을 만들면 URL 경로가 자동으로 생성되는 단순한 구조 덕분에 학습하기 쉬웠고, SSR, SSG, ISR 같은 렌더링 전략도 비교적 명확하게 사용할 수 있었음

 

공통 레이아웃 관리가 불편했음

기존에는 app.tsx에서 전체 공통 레이아웃을 감싸거나, 페이지마다 getLayout 패턴을 만들어 레이아웃을 적용하는 방식으로 사용했었음

페이지가 많아지고, 페이지마다 다른 레이아웃이 필요하거나, 중첩된 레이아웃을 구성해야 하는 경우 코드 구조가 복잡해지기 쉬웠음

 

 

페이지 단위 데이터 패칭에 묶여있음

getServerSideProps, getStaticProps 같은 함수는 페이지 파일에서 사용되었고, 이 함수에서 필요한 데이터를 준비한 뒤 페이지 컴포넌트에 props로 전달하는 구조였음

구조가 단순하고 명확하다는 장점이 있지만, 데이터 패칭의 중심이 개별 컴포넌트가 아니라 페이지에 가까웠음

 

 

스트리밍을 자연스럽게 쓰기 어려웠음

페이지를 렌더링하기 전에 필요한 데이터를 먼저 준비해야 했음

export async function getServerSideProps() {
  const user = await getWooseok();
  const posts = await getTtogi();
  const comments = await getComments();

  return {
    props: {
      wooseok,
      ttogi,
      comments,
    },
  };
}

export default function Page({ wooseok, ttogi, comments }) {
  return (
    <main>
      <UserWooseok user={wooseok} />
      <TtogiList posts={ttogi} />
      <CommentList comments={comments} />
    </main>
  );
}

 

wooseok과 ttogi는 빠르게 가져올 수 있는데, comments 요청이 오래 걸린다고 가정 한다면 UserWooseok과 TtogiList는 이미 보여줄 수 있는 상태인데도, comments가 준비될 때까지 전체 페이지 응답이 늦어질 수 있음

Pages Router는 서버에서 데이터를 가져와 HTML을 만든다는 장점도 있었지만, 페이지 전체가 하나의 렌더링 단위로 동작하는 경우가 많았음

 

 

리액트의 방향과 일치하지 않았음

리액트는 서버와 클라이언트를 명확히 분리하고 JS 번들을 최소한으로 내려받는 방향을 원했음

 

Pages Router는 기본적으로 pages 디렉터리의 각 파일을 하나의 페이지로 보고, 그 페이지 단위에서 getServerSideProps, getStaticProps 같은 함수를 통해 데이터를 가져오는 구조였음

export async function getServerSideProps() {
  const res = await fetch("parkttogi");
  const data = await res.json();

  return {
    props: {
      data,
    },
  };
}

export default function WooseokPage({ data }) {
  return (
    <div>
      <h1>우석이의 페이지</h1>
      <p>{data.message}</p>
    </div>
  );
}

 

즉 서버에서 데이터를 가져올 수는 있지만, 구조의 중심은 여전히 페이지 컴포넌트 였고, 브라우저에서 실행되는 React 컴포넌트를 기준으로 애플리케이션을 구성하는 방식에 가까웠음

서버 컴포넌트와 클라이언트 컴포넌트가 나누는 방향으로 발전하면서, Pages Router는 페이지 단위 데이터 패칭 구조를 흐름에 맞춰 자연스럽게 담기 어려웠음

 

React는 브라우저에 전달되는 JavaSript 번들을 줄이고 싶었음

 

 

Pages Router에서도 SSR을 통해 서버에서 HTML을 생성할  수 있었음, 하지만 페이지 컴포넌트는 결국 브라우저에서 Hydration되어야 했음

해당 컴포넌트와 관련된 React코드가 클라이언트 JavaScript 번들에 포함되는 구조였음

 

이러한 문제들로 Next.js팀은 대대적인 변화를 예고하고 App Router 를 공개하고 권장함

처음에 App Router는 실패한 변화로 받아들여졌나?

 

App Router가 처음 등장하고 사람들의 반응은 좋지 못했음

2023~24년 사이 많은 불만을 내비치는 글들이 많이 작성됨

Next.js는 Pages Router를 종료시키진 않을 거지만 App Router로 마이그레이션을 권장했고, 사람들은 이에 회의적이였음

 

공부를 하면서 Reddit이나 다른 개발자 커뮤니티의 2~3년 전 글을 보면 App Router에 대한 불편함을 많이 들어냄

 

정말로 App Router는 실패한 변화인가? 라는 주제로, 많은 개발자 선배님들은 무엇에 분노하고 있는가에 대해서 알아보자

 

  1. 기존의 Page Router에 비해 구조가 복잡하다
  2. Server Component와 Client Componet의 경계
  3. 캐싱 동작이 직관적이지 않음
  4. 기존의 사고방식과 달라졌다
  5. 작은 프로젝트에는 너무 과하게 비대하다
  6. Vercel 중심의 생태계에 종속된 느낌이다
  7. 초기에 불안했던 경험이 불신으로 남았다

어떤분은 "(24년 글)자기 회사에선 Page Router만 사용하고, App Router로 바꿀 계획은 전혀 없다 Page가 종료된다면 Next 자체를 떠날것 " 이라고도 말한다. 도대체 뭐가 그들을 이렇게 까지 화나게 했는가? (26년인데 이젠 생각이 바뀌지 않았을까?)

 

출처 : Github Next.js 토론장)

 

An honest opinion about the `App` vs `Pages` router · vercel next.js · Discussion #59373

I want to share my honest opinion about the direction that Next.js has been taking with the App router, because I really care about this project. I have been a user of Next.js since version 10 and ...

github.com

 

출처 : reddit  / 사람들은 왜 앱 라우터를 싫어할까요? )

 

Reddit의 nextjs 커뮤니티

nextjs 커뮤니티에서 이 게시물을 비롯한 다양한 콘텐츠를 살펴보세요

www.reddit.com

 

출처: Reddit /  앱 라우터보다 페이지 라우터를 선호하는 이유는 무엇인가요?

 

Reddit의 nextjs 커뮤니티

nextjs 커뮤니티에서 이 게시물을 비롯한 다양한 콘텐츠를 살펴보세요

www.reddit.com

 

 

 


 

App Router가 세상에 나온 이유 (Next.js 13)

Next.js 팀은 왜 Pages Router를 App Router로 변화 시키려 했는가?

RSC를 Next.js 라우팅 구조안에 제대로 녹이고, 레이아웃/데이터 패칭/스트리밍/SEO를 라우트 단위로 더 강하게 다루기 위해서 

 

Server Component를 기본 구조로 사용

서버에서 데이터를 가져오고, 비밀 키나 토큰을 클라이언트에 노출하지 않고, 브라우저로 보내는 JS 양을 줄이기 위한 목적

민감한 값은 서버에만 두고 클라이언트에는 필요한 결과만 전달할 수 있음

출처 : https://nextjs.org/blog/next-13

 

 

레이아웃 문제

Pages Router에서는 공통 레이아웃을 만들 수는 있지만, 라우트가 바뀔 때 레이아웃 상태를 자연스럽게 유지하거나, 중첩 레이아웃을 프레임워크 차원에서 깔끔하게 다루는 데 한계를 느꼈음

 

이를 보완 하고자 App Router에서는 layout.tsx를 라우트 계층마다 둘 수 있게 했고, 라우트 간 UI를 쉽게 공유하고, 상태를 유지하며, 비싼 리렌더링을 피하기 위한 것이라고 설명함

 

출처 : https://nextjs.org/blog/next-13

 

 

 

데이터 패칭을 함수가 아닌 컴포넌트 안에 넣으려고

RFC 컴포넌트 내부에서 데이터를 가져오고 프로미스를 처리하는 강력한 새로운 방법이라고 소개됨

  • getServerSideProps → SSR
  • getStaticProps → SSG
  • getStaticPaths → 동적 라우트에서 SSG 페이지 목록을 정함

기존에는 페이지 단위 함수가 중요했음

이를 fetch API를 통해 컴포넌트 레벨에서 데이터를 가져오고 캐시,재검증,SSR/SSG/ISR 비슷한 동작을 하나의 fetch API로 다룰 수 있게 했다고 설명함

출처: https://nextjs.org/blog/next-13

 

즉, 페이지 바깥에서 데이터를 준비해서 props로 넣는다보다, 서버 컴포넌트가 자기에게 필요한 데이터를 직접 가져오는 방향을 택한거임

 

반면 RSC는 서버에서만 실행되는 컴포넌트를 만들 수 있음.

→ 서버에서 데이터를 가져오고, 필요한 HTML 결과를 구성한 뒤, 클라이언트에는 상호작용에 필요한 최소한의 JS만 전달하는 방향

→브라우저가 굳이 실행하지 않아도 되는 코드는 서버에 남기고, 클라이언트에서 필요한 코드만 보내자는 방향에 가까움

 

React의 방향에 발맞추고자 함

React 18 부터는 브라우저에서만 실행되는 UI 라이브러리에서, 서버와 클라이언트가 역할을 나눠서 UI를 만드는 구조로 확장하는 방향을 원했음

 

출처: https://nextjs.org/blog/next-13

 

서버에서 할 수 있는 일은 서버에서 하고, 브라우저에서만 가능한 일은 Client Componet로 분리해서 처리하자

 

export async function getWooseok() {
  const res = await fetch("parkttogi", {cache: "no-store"});

  return res.json()
}

export default async function WooseokPage() {
    const data = await getWooseok();
    
  return (
    <div>
      <h1>우석이의 페이지</h1>
      <p>{data.message}</p>
    </div>
  );
}

 

Server Component 중심으로 바뀌는 React 방향을 라우팅 구조 안에 자연스럽게 담기 쉽게 변화함

 React는 더 이상 모든 컴포넌트가 브라우저로 전달되어 실행되는 구조만을 전제로하지 않음

 서버에서 실행될 컴포넌트와 클라이언트에서 실행될 컴포넌트를 구분하고, 각각의 역할을 나누는 방향으로 발전함

 

 

Streaming과 Suspense를 라우팅 구조에 넣으려고

App Router의 loading.tsx는 로딩 컴포넌트 파일 하나 만든게 아니라, React Suspense와 streaming을 라우트 구조에 붙인 형태

 

 

UI를 기다렸다가 한 번에 내보내는게 아니라, 렌더링 되는 단위대로 점진적으로 스트리밍할 수 있게 한다 라고 설명하고 있음

→ 사용자는 전체 페이지가 다 로드될 때가지 기다리지 않고, 먼저 준비된 부분부터 볼 수 있음

 

import { Suspense } from "react";

export default function Page() {
  return (
    <main>
      <UserWooseok />
      <TtogiList />

      <Suspense fallback={<div>우석이 불러오는 중...</div>}>
        <CommentList />
      </Suspense>
    </main>
  );
}

---------------------------------------------------------------------

export default function Loading() {
  return <div>우석이를 불러오는 중...</div>;
}

 

반면 App Router는 React의 Suspense와 Streaming을 라우팅 구조에 더 깊게 적용시켰음

 빠르게 준비되어 있는 UI를 먼저 렌더링하고, 오래 걸리는 CommentList 영역은 fallback UI를 보여준 뒤 데이터가 준비되면 나중에 채울 수 있음

 

 

출처 : Next.js 13 )

 

Next.js 13

Next.js 13 introduces layouts, React Server Components, and streaming in the app directory, as well as Turbopack, an improved image component, and the brand new font component.

nextjs.org

 

이러한 이유로 Vercel은 여러 변화를 주려 했고 그렇게 나온게 App Router


왜 Pages Router가 아니라 App Router로 개발 하셨나요?

 

" 왜 Pages Router가 아니라 App Router로 개발 하셨나요? " 

" 최신 기술 이라서요...?"

 

필자는 프론트엔드를 배우고 Next.js를 사용하기 시작했을 때부터 App Router만 사용했었음

→ 특별한 이유는 없었고, 이걸 배웠고 이게 최신 기술이고 공식 문서에서도 이 방식을 권장 했으니까

 물건을 샀으면 설명서대로 쓰는 게 자연스러운 방식이니까 Page Router를 고민할 필요가 없었음

 

출처 : https://nextjs.org/docs/pages?utm_source=chatgpt.com

 

하지만, 앞으로 일하다 보면 Pages Router를 쓰는 프로젝트를 할 수 있고, App Router로 마이그레이션을 하는 작업을 맡을 수도 있으니까 그때 "최신 기술이라서요" 라는 답변보다 각각의 배경을 알고 장단점을 파악하면 더 도움이 되지 않을까 싶어서 이 글을 작성하게 됨

 

 

 

 

 

반응형