Next.js App Router를 실무에서 언제 선택하고 언제 조심해야 하는가
Next.js App Router는 이제 단순한 새 라우터가 아니라, Next.js의 기본 문법에 가깝게 자리잡았습니다.
하지만 실무에서 App Router를 선택할 때는 "최신 방식이니까" 정도로 접근하면 금방 어려워집니다.
왜냐하면 App Router는 단순히 파일 구조가 바뀐 것이 아니라:
- 서버 컴포넌트
- 클라이언트 컴포넌트
- 레이아웃 계층
- 데이터 캐시
- 스트리밍
같은 개념이 한꺼번에 들어오기 때문입니다.
즉, App Router를 선택한다는 것은 새 폴더 구조를 고르는 것이 아니라, 렌더링 방식과 데이터 흐름의 기본 모델을 같이 선택하는 것에 가깝습니다.
이 글에서는 App Router가 실무에서 언제 잘 맞는지, 반대로 언제 조심해야 하는지를 담백하게 정리해보겠습니다.
한눈에 보면
먼저 짧게 정리하면 이렇습니다.
- App Router는 서버 중심 렌더링과 하이브리드 페이지 운영이 필요한 서비스에서 강합니다
- 공개 웹, 블로그, 커머스, SaaS처럼 서로 다른 렌더링 요구사항이 섞인 제품에 잘 맞습니다
- 반면 전부 클라이언트 상호작용 중심인 앱에서는 체감 이점보다 복잡도가 더 크게 느껴질 수 있습니다
- 특히 서버/클라이언트 경계, 캐시, 재검증 개념을 팀이 이해하지 못한 상태에서 도입하면 혼란이 커집니다
표로 보면 더 빠릅니다.
| 질문 | App Router가 잘 맞는 경우 | 조심해야 하는 경우 |
|---|---|---|
| 공개 페이지와 앱이 같이 있는가 | 잘 맞음 | 해당 없음 |
| SEO와 서버 렌더링이 중요한가 | 잘 맞음 | 필요가 약하면 이점이 줄어듦 |
| 서버 데이터와 캐시 전략을 함께 다뤄야 하는가 | 잘 맞음 | 전부 클라이언트 패칭이면 과할 수 있음 |
| 팀이 서버/클라이언트 경계를 이해하는가 | 도입 효과 큼 | 이해가 낮으면 혼란 가능 |
| 클라이언트 전용 라이브러리 의존이 큰가 | 일부 조심 필요 | 과도하면 마찰 큼 |
| 빠른 CRUD 위주의 내부 앱인가 | 경우에 따라 다름 | 단순 SPA가 더 효율적일 수 있음 |
App Router를 선택하면 무엇이 달라지나?
Pages Router와 비교했을 때 핵심 차이는 단순 라우팅이 아닙니다.
App Router는 기본적으로 다음 사고방식을 가져옵니다.
- 페이지는 서버에서 먼저 그릴 수 있다
- 꼭 필요한 부분만 클라이언트 컴포넌트로 내린다
- 데이터 패칭과 캐시 정책을 컴포넌트 가까이 둔다
- 중첩 레이아웃과 로딩 상태를 라우트 구조로 표현한다
예를 들어:
// app/dashboard/page.tsx
import { DashboardFilters } from './dashboard-filters';
export default async function DashboardPage() {
const summary = await getDashboardSummary();
return (
<>
<h1>{summary.title}</h1>
<DashboardFilters />
</>
);
}'use client';
type DashboardFiltersProps = {
// ...
};
export function DashboardFilters(_: DashboardFiltersProps) {
return <div>interactive filters</div>;
}이 구조는 "기본은 서버, 상호작용은 클라이언트"라는 분리를 더 자연스럽게 만듭니다.
언제 App Router가 잘 맞을까?
1. 공개 웹과 앱이 같이 있는 서비스
이 경우가 가장 대표적입니다.
예를 들어:
- 랜딩 페이지
- 가격 소개
- 블로그
- 로그인 후 대시보드
- 관리자 페이지
이런 제품은 한 가지 렌더링 방식으로 설명되지 않습니다.
- 공개 페이지는 SEO가 중요하고
- 블로그는 정적 생성이나 재검증이 효율적이고
- 대시보드는 상호작용이 중요하고
- 일부 관리 화면은 최신 데이터가 더 중요할 수 있습니다
App Router는 이 섞인 구조를 한 프로젝트 안에서 관리하기 좋습니다.
2. 서버에서 먼저 그려주는 것이 명확한 이점이 있을 때
검색 유입이 중요한 서비스나 초기 응답이 중요한 화면에서는 서버 렌더링이 실질적인 이점이 됩니다.
예를 들어 상품 상세나 아티클 페이지는 아래처럼 구성하기 좋습니다.
// app/products/[slug]/page.tsx
export default async function ProductPage({ params }: { params: { slug: string } }) {
const product = await getProduct(params.slug);
return (
<article>
<h1>{product.name}</h1>
<p>{product.summary}</p>
</article>
);
}이 구조는:
- 초기 HTML을 서버에서 만들고
- SEO를 확보하고
- 필요한 상호작용만 클라이언트로 남기는
식의 구성이 자연스럽습니다.
3. 레이아웃과 로딩 상태를 계층적으로 관리하고 싶을 때
App Router의 장점 중 하나는 레이아웃 구조입니다.
app/
layout.tsx
(marketing)/
layout.tsx
pricing/page.tsx
dashboard/
layout.tsx
page.tsx
loading.tsx이 구조가 좋은 이유는 단순히 파일이 예쁘기 때문이 아닙니다.
- 공통 레이아웃 책임이 분리되고
- 로딩 상태와 에러 처리 위치가 명확해지고
- 서비스 영역별 UI 골격을 나누기 쉬워집니다
즉, 화면 수가 많아질수록 체감이 커집니다.
4. 데이터 캐시와 재검증을 운영 정책으로 다뤄야 할 때
App Router에서는 데이터 패칭이 단순 구현이 아니라 운영 정책과 가깝습니다.
await fetch('https://api.example.com/posts', {
next: { revalidate: 300 },
});이 코드는 곧 아래 질문과 연결됩니다.
- 이 데이터는 5분까지 stale해도 되는가
- 응답 속도와 최신성 중 무엇을 우선할 것인가
- 어떤 페이지는 정적에 가깝게 둘 것인가
실무에서는 이 운영 판단을 코드 가까이에서 표현할 수 있다는 점이 꽤 큰 장점입니다.
5. 팀이 서버와 클라이언트 책임 분리에 익숙할 때
App Router는 팀이 아래 질문에 답할 수 있을수록 더 잘 맞습니다.
- 이 로직은 서버에 있어야 하는가
- 이 컴포넌트는 브라우저 API를 쓰는가
- 이 데이터는 요청마다 새로 받아야 하는가
- 이 화면은 어디까지 서버에서 만들고 어디부터 클라이언트에 맡길 것인가
팀이 이 경계를 이해하고 있으면 App Router는 구조를 더 분명하게 만들어줍니다.
언제 조심해야 할까?
1. 전부 클라이언트 상호작용 중심인 앱
예를 들어:
- 로그인 이후에만 쓰는 내부 툴
- 대시보드 중심의 SPA
- SEO가 거의 필요 없는 제품
이런 경우에는 App Router의 장점이 생각보다 크지 않을 수 있습니다.
물론 사용 못 하는 것은 아닙니다. 다만 아래 같은 상황이 생깁니다.
- 거의 모든 파일에
'use client'가 붙고 - 서버 컴포넌트 이점은 작고
- 오히려 경계만 복잡하게 느껴질 수 있습니다
이럴 때는 단순한 React SPA가 더 효율적일 수 있습니다.
2. 팀이 서버/클라이언트 경계에 익숙하지 않을 때
App Router에서 자주 생기는 혼란은 기능 부족이 아니라 사고방식 충돌입니다.
예를 들어 아래 코드는 서버 컴포넌트에서 바로 쓸 수 없습니다.
import { useEffect, useState } from 'react';
export default function Page() {
const [open, setOpen] = useState(false);
useEffect(() => {
console.log(window.location.href);
}, []);
return <button onClick={() => setOpen(true)}>open</button>;
}왜냐하면 브라우저 전용 로직이기 때문입니다. 그래서 'use client'를 붙여야 합니다.
문제는 팀이 이 기준을 이해하지 못하면:
- 왜 어떤 파일은 동작하고 어떤 파일은 안 되는지
- 왜 props 직렬화 제약이 생기는지
- 왜 서버에서 읽은 값을 클라이언트로 바로 넘기는 데 제한이 있는지
를 계속 헷갈리게 됩니다.
즉, App Router는 문법보다 개념 학습 비용이 더 큰 편입니다.
3. 클라이언트 전용 라이브러리 의존이 강할 때
차트, 에디터, 드래그 앤 드롭, 브라우저 API 의존 라이브러리가 많으면 조심해야 합니다.
이런 라이브러리는 종종:
windowdocument- 레이아웃 측정
- 브라우저 이벤트
에 의존합니다.
그러면 결국 해당 영역은 클라이언트 컴포넌트로 내려야 하고, 서버 컴포넌트 구조의 장점이 줄어듭니다.
즉, 제품의 핵심 UI가 대부분 브라우저 상호작용 위에 서 있다면 App Router의 이점을 냉정하게 다시 봐야 합니다.
4. 캐시와 재검증을 명확히 이해하지 못한 채 도입할 때
App Router는 편한 동시에 오해하기 쉬운 지점이 있습니다.
- 왜 데이터가 바로 안 바뀌지?
- 왜 어떤 요청은 캐시되고 어떤 요청은 아닌가?
- 왜 배포 후에도 이전 데이터가 보이지?
이런 질문은 대부분 캐시와 재검증 정책을 팀이 명확히 잡지 않았을 때 나옵니다.
예를 들어 실무에서는 아래를 반드시 구분해야 합니다.
- 요청마다 최신 데이터가 필요한가
- 일정 주기 캐시가 가능한가
- 수동 재검증이 필요한가
이 기준 없이 App Router를 도입하면 "프레임워크가 이상하다"는 오해가 쉽게 생깁니다.
5. 기존 Pages Router 프로젝트를 무리하게 한 번에 옮길 때
마이그레이션도 조심해야 합니다.
기존 프로젝트가 아래에 많이 기대고 있다면:
getServerSidePropsgetStaticPropspages/api- 오래된 클라이언트 중심 패턴
App Router로 한 번에 전환하는 것은 생각보다 비용이 큽니다.
특히 화면 수가 많고 팀이 바쁜 상태라면, 전면 전환보다 신규 영역부터 App Router를 도입하는 방식이 현실적일 수 있습니다.
실무 판단 기준으로 다시 정리하면
아래 질문에 예가 많을수록 App Router가 잘 맞을 가능성이 큽니다.
- 공개 페이지와 로그인 후 앱을 한 제품 안에서 같이 운영하는가
- SEO가 중요한 페이지가 존재하는가
- 서버에서 먼저 렌더링하는 이점이 분명한가
- 캐시와 재검증을 운영 정책으로 다뤄야 하는가
- 팀이 서버/클라이언트 경계에 대한 학습을 감당할 수 있는가
반대로 아래 질문에 예가 많다면 더 조심해서 봐야 합니다.
- 거의 모든 화면이 브라우저 상호작용 중심인가
- 핵심 라이브러리 대부분이 클라이언트 전용인가
- SEO 필요가 약한가
- 팀이 서버 컴포넌트와 캐시 개념에 익숙하지 않은가
- 지금 필요한 것은 구조 고도화보다 빠른 화면 구현인가
개인적으로 추천하는 도입 방식
실무에서는 App Router를 "무조건 전면 도입"보다 아래처럼 보는 편이 더 안전합니다.
잘 맞는 방식
- 신규 프로젝트에서 시작부터 도입
- 공개 웹, 블로그, 문서, 커머스 상세 같은 영역부터 도입
- 팀이 서버/클라이언트 경계를 같이 학습하면서 규칙을 정리
조심할 방식
- 기존 프로젝트 전체를 단기간에 전면 전환
- 개념 정리 없이
'use client'만 남발하는 방식 - 캐시 정책 기준 없이 일단 fetch부터 바꾸는 방식
즉, App Router는 도입 자체보다 어떤 영역부터, 어떤 기준으로, 팀이 얼마나 이해한 상태에서 가져가는가가 더 중요합니다.
정리하면
Next.js App Router를 실무에서 언제 선택해야 하는가를 한 줄로 줄이면 이렇습니다.
서버 중심 렌더링, 하이브리드 페이지 운영, 계층형 레이아웃, 캐시 정책 관리가 중요한 서비스라면 App Router는 꽤 좋은 선택지입니다.
반대로 언제 조심해야 하는가를 한 줄로 줄이면 이렇습니다.
전부 클라이언트 상호작용 중심이거나, 팀이 서버/클라이언트 경계와 캐시 개념을 아직 소화하지 못한 상태라면 App Router는 복잡도부터 체감될 수 있습니다.
결국 중요한 것은 "App Router가 최신인가"가 아니라, 우리 서비스와 팀이 이 모델을 소화했을 때 실제 이점이 생기는가입니다.
