Blog
HomePostsTagsCategories
© 2026 Hyeonseok An. All rights reserved.
GitHubEmailInstagram
Home
Develop
Next.js App Router로 깔끔한 프로젝트 구조 만들기

Next.js App Router로 깔끔한 프로젝트 구조 만들기

August 16, 2025
Loading...
Next.jsApp routerOptimizeTILFront-end
Cover image for Next.js App Router로 깔끔한 프로젝트 구조 만들기
Next.js 13에서 도입된 App Router는 단순히 새로운 라우팅 방식이 아닙니다. 프로젝트의 구조와 개발 패턴 자체를 혁신적으로 바꿔놓은 게임 체인저죠. 복잡해지기 쉬운 대규모 애플리케이션을 어떻게 체계적으로 관리할 수 있는지, 실무에서 바로 적용할 수 있는 패턴들을 정리해보겠습니다.

파일 시스템이 곧 라우터

App Router의 핵심은 파일 기반 라우팅입니다. 폴더를 만들면 그게 곧 URL 경로가 되고, 그 안에 어떤 파일을 넣느냐에 따라 해당 경로의 역할이 결정됩니다.

핵심 파일들의 역할

page.tsx - UI의 진입점
// app/dashboard/page.tsx export default function DashboardPage() { return <div>대시보드 페이지</div>; } // → /dashboard URL에서 렌더링
route.ts - API 엔드포인트
// app/api/users/route.ts export async function GET() { return Response.json({ users: [] }); } export async function POST(request: Request) { const data = await request.json(); // 사용자 생성 로직 return Response.json({ success: true }); } // → /api/users에서 GET, POST 요청 처리
이렇게 단순한 규칙으로 복잡한 라우팅 설정 없이도 직관적인 구조를 만들 수 있습니다.

기능 단위로 코드 정리하기

관련된 기능들을 하나의 폴더로 묶어 관리하는 기능적 그룹화는 코드 응집도를 높이는 핵심 전략입니다.
app/ ├── auth/ │ ├── login/route.ts # 로그인 API │ ├── signup/route.ts # 회원가입 API │ ├── actions.ts # 인증 관련 서버 액션 │ └── utils.ts # 인증 유틸리티 ├── posts/ │ ├── create/route.ts # 포스트 생성 API │ ├── [id]/route.ts # 특정 포스트 API │ └── actions.ts # 포스트 관련 서버 액션
이런 구조의 장점은 명확합니다:
  • 높은 응집도: 관련 코드가 한 곳에 모여 있어 찾기 쉬움
  • 낮은 결합도: 각 기능이 독립적으로 관리됨
  • 쉬운 확장: 새로운 기능 추가 시 해당 폴더만 건드리면 됨

라우트 그룹으로 구조 최적화하기

여기서 App Router의 진짜 강력함이 나타납니다. 라우트 그룹을 사용하면 파일 시스템 구조와 URL 구조를 분리할 수 있습니다.

기본 개념

폴더 이름을 괄호 ()로 묶으면, 이 폴더는 URL 경로에 영향을 주지 않으면서 코드 정리 목적으로만 사용됩니다.
app/ ├── (api)/ # URL에 영향 없음 │ └── auth/ │ └── login/route.ts └── (ui)/ # URL에 영향 없음 └── login/ └── page.tsx # 결과 URL: # /auth/login (API) # /login (UI 페이지)

실무 적용: API와 UI 분리

변경 전 - 혼재된 구조:
app/ ├── auth/ # API인지 UI인지 불분명 ├── login/ # 마찬가지로 애매함 └── dashboard/
변경 후 - 명확한 분리:
app/ ├── (api)/ │ └── auth/ │ ├── login/route.ts │ ├── logout/route.ts │ └── refresh/route.ts └── (ui)/ ├── login/page.tsx ├── signup/page.tsx └── dashboard/page.tsx
이제 코드를 보는 순간 API 코드인지 UI 코드인지 명확히 구분됩니다.

UI 라우트 그룹의 고급 활용법

1. 레이아웃별 페이지 그룹화

웹사이트의 다른 섹션에 서로 다른 레이아웃을 적용할 때 매우 유용합니다.
// app/(marketing)/layout.tsx - 마케팅 사이트 레이아웃 export default function MarketingLayout({ children, }: { children: React.ReactNode; }) { return ( <div> <MarketingHeader /> {children} <MarketingFooter /> </div> ); } // app/(dashboard)/layout.tsx - 대시보드 레이아웃 export default function DashboardLayout({ children, }: { children: React.ReactNode; }) { return ( <div className="flex"> <Sidebar /> <main>{children}</main> </div> ); }
app/ ├── (marketing)/ │ ├── page.tsx # / (홈페이지) │ ├── about/page.tsx # /about │ └── layout.tsx # 마케팅 레이아웃 ├── (dashboard)/ │ ├── dashboard/page.tsx # /dashboard │ ├── settings/page.tsx # /settings │ └── layout.tsx # 대시보드 레이아웃 └── layout.tsx # 루트 레이아웃

2. 기능별 페이지 정리

app 디렉토리 최상단이 너무 복잡해지는 것을 방지할 수 있습니다.
app/ ├── (auth)/ │ ├── login/page.tsx │ ├── signup/page.tsx │ ├── forgot-password/page.tsx │ └── layout.tsx # 인증 페이지 공통 레이아웃 ├── (shop)/ │ ├── products/page.tsx │ ├── cart/page.tsx │ └── checkout/page.tsx └── page.tsx # 홈페이지

최적화된 프로젝트 구조 제안

모든 개념을 종합하면 다음과 같은 구조를 권장합니다:
app/ ├── (api)/ # 🔵 API 라우트 그룹 │ ├── auth/ │ │ ├── login/route.ts │ │ └── logout/route.ts │ ├── posts/ │ │ ├── route.ts │ │ └── [id]/route.ts │ └── users/route.ts │ ├── (marketing)/ # 🟢 마케팅 사이트 │ ├── page.tsx # / │ ├── about/page.tsx # /about │ ├── pricing/page.tsx # /pricing │ └── layout.tsx │ ├── (app)/ # 🟡 메인 애플리케이션 │ ├── dashboard/page.tsx # /dashboard │ ├── posts/ │ │ ├── page.tsx # /posts │ │ └── [id]/page.tsx # /posts/[id] │ └── layout.tsx │ ├── (auth)/ # 🟠 인증 관련 페이지 │ ├── login/page.tsx # /login │ ├── signup/page.tsx # /signup │ └── layout.tsx │ └── layout.tsx # 루트 레이아웃

컴포넌트와 서버 액션의 Colocation

"코드는 사용되는 곳에 최대한 가깝게" - 이는 현대 소프트웨어 개발의 핵심 원칙입니다. App Router에서는 이를 매우 자연스럽게 구현할 수 있습니다.

전용 액션의 배치

특정 컴포넌트에서만 사용하는 서버 액션이라면, 그 컴포넌트 바로 옆에 두는 것이 최선입니다.
// components/blog/PostFeed.tsx 'use client'; import { loadMorePosts } from './PostFeed.actions'; export default function PostFeed() { const [posts, setPosts] = useState([]); const handleLoadMore = async () => { const newPosts = await loadMorePosts(); setPosts(prev => [...prev, ...newPosts]); }; return ( <div> {posts.map(post => <PostCard key={post.id} post={post} />)} <button onClick={handleLoadMore}>더 보기</button> </div> ); }
// components/blog/PostFeed.actions.ts 'use server'; export async function loadMorePosts() { // PostFeed 컴포넌트 전용 로직 const posts = await db.posts.findMany({ take: 10, orderBy: { createdAt: 'desc' } }); return posts; }
디렉토리 구조:
components/ └── blog/ ├── PostFeed.tsx # 클라이언트 컴포넌트 ├── PostFeed.actions.ts # 전용 서버 액션 ├── PostCard.tsx └── PostCard.actions.ts

하이브리드 접근법

실제 프로젝트에서는 두 가지 방식을 조합해서 사용합니다:
1. 공통 액션 - 중앙화
// app/(api)/posts/actions.ts 'use server'; export async function createPost(data: PostData) { // 여러 곳에서 사용하는 공통 로직 } export async function deletePost(id: string) { // 여러 곳에서 사용하는 공통 로직 }
2. 전용 액션 - 컴포넌트 옆에
// components/PostEditor/PostEditor.actions.ts 'use server'; export async function autosaveDraft(content: string) { // PostEditor에서만 사용하는 자동저장 로직 }

실무에서의 마이그레이션 전략

기존 Pages Router에서 App Router로 전환할 때는 점진적 접근이 중요합니다:

1단계: 라우트 그룹으로 기존 구조 정리

app/ ├── (legacy)/ # 기존 페이지들 │ └── ...기존 파일들 └── (new)/ # 새로운 App Router 페이지들 └── ...새 파일들

2단계: 기능별로 하나씩 마이그레이션

app/ ├── (api)/ # ✅ API 라우트 완료 ├── (auth)/ # ✅ 인증 페이지 완료 ├── (dashboard)/ # 🚧 작업 중 └── (legacy)/ # ⏳ 아직 마이그레이션 안 된 페이지들

3단계: 최종 구조로 정리

모든 마이그레이션이 완료되면 라우트 그룹을 최적화하고 불필요한 레거시 코드를 제거합니다.

마무리

Next.js App Router는 단순한 라우팅 도구를 넘어서 프로젝트 아키텍처를 설계하는 강력한 도구입니다. 라우트 그룹과 colocation 패턴을 활용하면:
  • 명확한 코드 구조: API와 UI가 깔끔하게 분리됨
  • 높은 유지보수성: 관련 코드가 한 곳에 모여 있어 수정이 쉬움
  • 확장성: 새로운 기능 추가 시 기존 구조를 해치지 않음
  • 팀 협업: 코드의 위치가 예측 가능해져 팀 작업이 수월함
특히 대규모 프로젝트에서 이런 구조의 진가가 드러납니다. 처음에는 조금 복잡해 보일 수 있지만, 프로젝트가 커질수록 이 투자가 얼마나 가치 있는지 체감하게 될 것입니다.

참고 자료

공식 문서

  • Next.js App Router 공식 문서 - App Router의 모든 기능과 개념
  • Next.js 라우팅 가이드 - 파일 기반 라우팅 상세 가이드
  • Next.js 라우트 그룹 - 라우트 그룹 활용법
  • Next.js 서버 액션 - 서버 액션과 뮤테이션

추가 학습 자료

  • Next.js 13 마이그레이션 가이드 - Pages Router에서 App Router로 전환
  • React 서버 컴포넌트 - App Router의 기반 기술
  • Next.js Best Practices - 파일 구성 모범 사례

다음 포스트에서는 App Router의 고급 기능인 Parallel Routes와 Intercepting Routes를 다뤄보겠습니다.
 
Tags:Next.jsApp routerOptimizeTILFront-end