본문 바로가기
Study

[Next.js] App Router vs Pages Router (feat. 달라진 폴더 구조)

by 안자두 2025. 1. 19.

1. 계기

Next.js로 새로운 프로젝트를 진행 중인데, 최신 버전으로 설치하여 14 버전을 사용하게 되었다.
이전(몇 넌 전...) 프로젝트를 진행했던 경험과 구글링을 참고해 폴더 구조를 구성하다 보니, 뭔가 라우팅이 원활하게 되지 않았다.

문제를 알 수 없어 검색을 해보다, Next.js 14 버전은 Next.js 13부터 생긴 App Router를 기본적으로 사용하고 있어, 내가 이전에 사용했던 Pages Router 기반의 폴더 구조를 중간중간 참고하려고 하니 충돌이 생겼던 것이다.

이참에, Next.js의 App Router와 Pages Router에 대해 비교해 보고 정리하고자 한다.


2. 개발 환경

  • Next.js 버전: 14
  • Node.js 버전: 18.16.0

3. Pages Router

우선 기존의 Pages Router에 대해 알아보자.
Pages Router는 Next.js의 초기 라우팅 방식으로, 프로젝트의 pages 디렉토리를 기반으로 동작한다.

1) 라우팅 경로

Pages Router는 pages 디렉터리 내의 파일 이름이 URL 경로가 된다. 예를 들어, pages 폴더 하위에 about.js 파일을 두면, 이 페이지의 라우팅 경로는 /about이 된다. 마찬가지로 pages/detail/about.js 구조라면 /detail/about처럼 중첩된 구조를 갖게 된다.

2) 데이터 패칭 메서드

서버 사이드 렌더링를 구현하기 위한 getServerSideProps와 정적 생성을 구현하기 위한 getStaticProps 데이터 패칭 메서드를 갖는다.

getServerSideProps
페이지 요청이 있을 때마다 서버에서 실행되며, 데이터를 가져오고 페이지를 렌더링 한다. 요청할 때마다 새로운 데이터를 제공하기 때문에, 실시간 데이터가 필요할 때 적합하다.
또한, 서버에서 완전히 렌더링된 HTML이 반환되기 때문에 SEO에 유리하다.

getStaticProps
빌드 시점에 실행되어 정적인 HTML 파일을 생성한다. 따라서, 데이터가 자주 변하지 않는 경우 성능 최적화에 유리하다.
또한, 이미 빌드된 HTML을 클라이언트에게 바로 제공하기 때문에, 페이지 로드 속도가 매우 빠르고 SEO에도 유리하다. ISR을 지원하여 일정 시간마다 정적 페이지를 갱신할 수 있다.

3) APP과 Document 커스텀

pages/_app.js pages/_document.js를 통해 전역 설정과 HTML 구조를 커스터마이징 할 수 있다.

 

요약하자면, Pages Router는 직관적인 파일 기반 라우팅을 지원하며, App Router의 등장 이전까지 사용되었기 때문에, 많은 레퍼런스가 존재한다. 또한, 많은 버전들을 함께해왔기 때문에 안정적인 환경을 제공해준다는 장점이 있다.

하지만, 복잡한 레이아웃에 대한 관리가 어렵다. 또한, Server Components 같은 최신 React 기능에서는 사용이 어렵다.


4. App Router

App Router는 기존의 Pages Router와는 다르게 React Server Components를 활용하여 더 강력하고 유연한 서버-클라이언트 통합을 지원한다.
기본적으로 app 디렉토리를 기반으로 동작한다.

1) 라우팅 경로

App Router는 app 디렉토리 내의 폴더 이름이 URL 경로가 된다. 예를 들어, app 폴더 하위에 about 폴더와 page.js 파일을 두면, 이 페이지의 라우팅 경로는 /about이 된다. 마찬가지로 app/detail/about/page.js 구조라면 /detail/about처럼 중첩된 구조를 갖게 된다. 
만약, 레이아웃만을 위한 폴더 중첩이 필요하다면, 폴더명을 소괄호 내에 작성하여 라우팅 경로에서 배제할 수 있다. app/detail/(about)/page.js 구조의 경우, about은 라우팅 경로에서 제외되어, /detail이 된다.
또한, 동적 라우팅이 필요한 경우, [id] 이런 식으로 폴더를 생성한다면, id로 넘긴 값이 라우팅 경로로 추가된다.

2) React Server Components

App Router에서는 기본적으로 서버 컴포넌트 방식이다. 만약, 클라이언트 로직이 필요하다면, 파일 상단에 `'use client'`를 작성해주어야 한다. 이때, 클라이언트 로직이 필요한 부분만 별도의 컴포넌트로 분리하면, 해당 부분만 클라이언트 단에서 처리하기 때문에, 다른 로직은 건드리지 않아, 성능 향상에 도움을 준다.

3) 파일 역할 구분

라우팅을 폴더 이름을 기반으로 하면 폴더 이름은 어떻게 지어야 할까? App Router에서는 파일 이름으로 역할을 구분할 수 있다. 
먼저, 위에서 라우팅 얘기를 할 때 말했던 page.js. page.js는 해당 경로의 메인 페이지가 된다. 이전 React에서 사용하던 index.js와 비슷하다고 생각했다.
그리고 레이아웃의 경우, layout.js이라는 파일을 생성하면, 해당 레이아웃은 현재 폴더 하위의 모든 페이지에 적용된다. 따라서, 공통 레이아웃을 구현할 때 유용하다.
마지막으로, loading.js 파일 생성으로 로딩 상태를 처리할 수도 있다.

 

App Router는 서버 렌더링과 클라이언트 렌더링 간의 경계가 명확하다. 또한, 레이아웃 구성과 관리가 용이하며, Pages Router에서는 어렵다고 했던 최신 React 기능과도 완벽한 호환성을 보인다.

하지만, 이전 Pages Router에 익숙한 개발자에게는 학습 곡선이 높으며, 아직까지 Pages Router에 비해 레퍼런스가 많이 부족하다는 단점이 있다.


5. App Router 프로젝트 적용

아래는 내가 시작한 프로젝트의 폴더 구조이다.

App Router 구조로, src 하위의 app 폴더 내에는, 최대한 라우팅되는 페이지만 있을 수 있도록 하였다.
그리고 세부 로직은 별도의 components 폴더를 생성해, 위에서 언급한 클라이언트 로직이 있는 컴포넌트를 비롯한 로직을 분리한 컴포넌트들을 추가했다.

(main)의 경우, 중첩된 폴더가 많지만, 실제로는 소괄호로 작성된 폴더는 라우팅 경로에 포함되지 않기 때문에 경로가 그다지 깊지 않다. 나는 레이아웃만을 사용하기 위해 폴더를 만든 경우, 소괄호를 사용해 주었다.

저렇게 폴더마다 layout 파일을 추가해 공통 레이아웃을 여러 개 만들 수도 있다! 내가 설계할 때는, 전체 프로젝트의 이미지를 먼저 생각한 다음, 각 공통 컴포넌트를 기준으로 레이아웃을 분리했다.

app 폴더 중점으로 봐주세용

물론, 폴더 구조는 프로젝트를 진행하는 사람마다, 팀마다 다를 수 있기 때문에 참고용으로만 봐주시길 바란다.


마치며

App Router는 Pages Router보다 현대적인 기능과 유연성을 제공한다. 이전과는 달라 조금 헷갈릴 수도 있지만, 처음 적용만 익힌다면 이후부터는 편하게 사용할 수 있는 것 같다.

728x90