Next.js로 프로젝트를 만들다 보면 한 번쯤은 이런 생각을 하게 된다. “나는 app Router를 쓰고 있는데, 굳이 src 폴더가 필요할까?”
사실 나도 처음엔 그런 고민을 해본 적이 없었다. 그런데 공식 문서를 보다 보니 이런 문장이 눈에 들어왔다.
"Next.js also supports placing application code under the src folder. This seperates application code from project configuration files."
즉, Next.js는 src 폴더를 강제하지 않지만, 지원한다는 뜻이었다. 그리고 그 이유는 “코드와 설정을 분리하기 위해서”라고 한다.
이건 단순히 폴더를 옮기는 문제가 아니라, 프로젝트를 어떻게 구조적으로 설계하느냐의 문제라는 것을 깨달았다.
src 폴더의 존재 이유
src는 source code, 즉 애플리케이션의 핵심 소스만 모아두는 폴더다. 대부분의 React나 Vue 프로젝트에서는 이미 당연하게 쓰이고 있지만, Next.js에서는 필수 개념은 아니었다.
Next.js는 기본적으로 루트 디렉터리에 app(또는 pages) 폴더만 있으면 동작한다. 하지만 프로젝트가 커지고 설정 파일이 늘어날수록 루트 디렉터리는 점점 어수선해진다.
my-project/
├── app/
├── public/
├── next.config.js
├── package.json
├── tsconfig.json
├── .env.local
이런 구조에서는 app 폴더가 설정 파일들 사이에 묻혀서 “어디까지가 애플리케이션 코드인지” 한눈에 보기 어려워진다.
그래서 많은 팀이 src 폴더를 추가한다. 이렇게 하면 코드의 역할이 훨씬 명확해진다.
my-project/
├── src/
│ └── app/
├── public/
├── next.config.js
├── package.json
└── tsconfig.json
루트에는 “환경과 설정”, src 안에는 “애플리케이션 코드”를 배치한다. 이 단순한 분리만으로도 프로젝트가 훨씬 깔끔해진다.
app 폴더 안에 page.tsx 말고 다른 컴포넌트를 넣어도 될까?
처음엔 나도 app 폴더 안에서 페이지별로 컴포넌트나 타입 파일을 함께 관리했다. 예를 들어 /dashboard/page.tsx 옆에 DashboardCard.tsx나 types.ts를 두는 식이었다. 겉보기엔 편해 보이지만, 프로젝트가 커질수록 폴더 구조가 복잡해지고
라우팅과 UI 코드가 뒤섞이기 시작했다. 그때 동료 한 분이 이렇게 조언해주셨다. "“app 폴더는 라우팅 전용으로 두고, 페이지에서 사용하는 컴포넌트는 src 바로 아래에 따로 분리하는 방법도 있어요."
app/은 “라우팅을 담당하는 영역”, src 바로 아래는 “공용 코드와 로직을 담는 영역”으로 역할이 명확해질 수 있다는 것을 알게 되었다.
src/
├── app/
│ ├── layout.tsx
│ ├── page.tsx
│ └── dashboard/
│ └── page.tsx
│
├── components/ → 공용 UI 컴포넌트
├── hooks/ → 커스텀 훅
├── lib/ → fetcher, 유틸, API
├── store/ → jotai, zustand 등 전역 상태
├── types/ → 타입 정의
└── utils/ → 공통 유틸 함수
이 구조에서 app은 라우트와 서버 컴포넌트 전용, 그 외의 폴더들은 클라이언트 코드 및 공용 로직 전용으로 동작한다.
이 구조의 장점은 무엇일까?
책임이 명확하다.
ap은 페이지와 라우팅에 집중할 수 있기 때문에 유지보수가 쉬워진다. 또한, UI나 로직이 변경되어도 라우트 구조에는 영향을 주지 않는다.
또한, 서버/클라이언트 컴포넌트 구분이 자연스럽다. app 내부는 기본적으로 서버 컴포넌트, src/components는 'use client' 선언을 통해 클라이언트 전용으로 분리되기 떄문이다.
마무리하며
Next.js에서 src는 필수가 아니다.
하지만 src 폴더를 도입하면 코드의 역할이 분리되고, 프로젝트의 의도가 드러난다.
app은 라우팅을 담당하는 폴더, src의 나머지 폴더들은 비즈니스 로직과 UI를 담당하는 코드로 구성하면, 프로젝트의 복잡도는 줄어든다.
'Next' 카테고리의 다른 글
| mutateAsync 도입기 (0) | 2025.11.14 |
|---|---|
| Strict Mode와 useEffect의 반복 실행 이슈 정리 (0) | 2025.10.27 |
| Loading.jsx와 Suspense fallback의 차이 (0) | 2025.07.01 |
| bodySizeLimit 설정 (0) | 2025.06.16 |