Next.js 프로젝트 구조 (Project Structure and Organization)

Next.js 공식 문서 Project structure and organization 페이지를 기반으로, 폴더·파일 컨벤션과 프로젝트 정리 방법을 요약한 자료입니다.


1. 폴더 및 파일 컨벤션 (Folder and file conventions)

1.1 상위(top-level) 폴더

상위 폴더는 애플리케이션 코드와 정적 자산을 나누는 기준이 됩니다.

폴더설명
app/App Router용 폴더. layout.tsx, page.tsx 등을 사용하여 라우트와 UI를 구성합니다.
pages/기존 Pages Router용 폴더. 새 프로젝트에서는 app/ 사용이 권장됩니다.
public/정적 자산(이미지, 폰트 등)을 두는 폴더. URL 기준 루트(/)에서 바로 서빙됩니다.
src/선택적 애플리케이션 소스 폴더. app/과 기타 코드를 src 아래로 모아 루트 설정 파일들과 분리할 수 있습니다.

1.2 상위(top-level) 파일

상위 파일들은 애플리케이션 설정, 의존성 관리, 프록시 실행, 모니터링, 환경 변수 정의 등에 사용됩니다.

  • next.config.js : Next.js 설정 파일
  • package.json : 의존성과 npm/pnpm 스크립트 정의
  • instrumentation.ts : OpenTelemetry 및 기타 계측 설정
  • proxy.ts : Next.js 요청 프록시 설정
  • .env, .env.local, .env.production, .env.development : 환경 변수 파일
  • eslint.config.mjs : ESLint 설정 파일
  • .gitignore : Git에서 무시할 파일/폴더 목록
  • next-env.d.ts : Next.js용 TypeScript 선언 파일
  • tsconfig.json / jsconfig.json : TypeScript/JavaScript 설정 파일

1.3 라우팅 파일 (Routing files)

특수 파일 이름은 특정 라우팅 역할을 담당합니다.

파일 이름확장자역할
layout.js .jsx .tsx라우트 세그먼트의 레이아웃(공통 UI)
page.js .jsx .tsx실제 페이지 컴포넌트(공개 라우트)
loading.js .jsx .tsxSuspense 로딩 UI (스켈레톤 등)
error.js .jsx .tsx해당 세그먼트용 에러 경계 UI
global-error.js .jsx .tsx앱 전체에 적용되는 전역 에러 UI
not-found.js .jsx .tsx404 등 “찾을 수 없음” UI
route.js .tsAPI 엔드포인트(HTTP 핸들러)
template.js .jsx .tsx다시 렌더링되는 레이아웃(템플릿)
default.js .jsx .tsx병렬 라우트의 기본/폴백 페이지

2. 라우팅 구조 (Routing structure)

2.1 중첩 라우트 (Nested routes)

  • 각 폴더가 URL 세그먼트 하나에 대응합니다.
  • 폴더를 중첩하면 URL도 중첩됩니다.
  • 어느 수준에서든 layout 파일이 있으면, 해당 레이아웃이 자식 세그먼트를 감싸게 됩니다.
  • 특정 세그먼트에 page 또는 route 파일이 존재할 때 그 경로가 “공개 라우트”가 됩니다.

예시:

파일 경로URL설명
app/layout.tsx(전체)모든 라우트를 감싸는 루트 레이아웃
app/blog/layout.tsx/blog 이하블로그 섹션 전용 레이아웃
app/page.tsx/루트 페이지
app/blog/page.tsx/blog블로그 메인 페이지
app/blog/authors/page.tsx/blog/authors블로그 작성자 목록 등

2.2 동적 라우트 (Dynamic routes)

대괄호([])를 이용해 세그먼트를 파라미터로 만들 수 있습니다.

  • [segment] : 한 개의 파라미터
  • [...segment] : 여러 세그먼트를 한 번에 받는 “catch‑all”
  • [[...segment]] : 파라미터가 없어도 되는 “optional catch‑all”

예시:

파일 경로매칭되는 URL 예
app/blog/[slug]/page.tsx/blog/my-first-post
app/shop/[...slug]/page.tsx/shop/clothing, /shop/clothing/shirts
app/docs/[[...slug]]/page.tsx/docs, /docs/layouts-and-pages, /docs/api-reference/use-router

2.3 라우트 그룹과 프라이빗 폴더 (Route groups & private folders)

  • Route group: (folderName)

    • URL에는 포함되지 않고, 폴더 구조와 레이아웃 구성을 위한 용도로만 사용됩니다.
    • 예: app/(marketing)/page.tsx → 실제 URL은 /
  • Private folder: _folderName

    • 라우팅 시스템에서 완전히 제외되는 폴더입니다.
    • 라우트가 아닌 UI 컴포넌트나 유틸 파일을 같은 세그먼트 안에 안전하게 모아둘 수 있습니다.
    • 예: app/blog/_components/Post.tsx, app/blog/_lib/data.ts 는 라우트로 노출되지 않습니다.

3. 병렬 라우트와 인터셉트 라우트 (Parallel & Intercepted Routes)

특정 UI 패턴(슬롯 레이아웃, 모달 라우팅 등)을 구현하기 위한 기능입니다.

3.1 병렬 라우트 (Parallel routes)

  • @slot 패턴으로 이름이 붙은 폴더를 만들면, 부모 레이아웃에서 여러 슬롯에 서로 다른 라우트를 동시에 렌더링할 수 있습니다.
    • 예: 사이드바 + 메인 콘텐츠 구조

3.2 인터셉트 라우트 (Intercepted routes)

다른 라우트를 현재 레이아웃 안에서 “가로채서” 렌더링하지만, URL은 그대로 유지하는 패턴입니다. 보통 리스트 위에 상세 모달을 띄울 때 사용합니다.

문서에서 소개하는 패턴:

패턴의미 / 용도 예시
@folder이름 있는 슬롯. 사이드바와 메인 영역 등 병렬 렌더링
(.)folder같은 레벨의 라우트를 모달 등으로 가로채기
(..)folder부모 레벨의 자식 라우트를 오버레이로 표시
(..)(..)folder두 단계 위에서부터 자식을 인터셉트
(...)folder루트 기준으로 임의의 라우트를 현재 뷰 안에서 표시

4. 메타데이터 파일 컨벤션 (Metadata file conventions)

4.1 앱 아이콘 (App icons)

이름유형설명
favicon.ico파비콘 파일
icon.ico .jpg .jpeg .png .svg앱 아이콘 정적 파일
icon.js .ts .tsx코드를 통해 생성하는 앱 아이콘
apple-icon.jpg .jpeg .png애플 기기용 아이콘 정적 파일
apple-icon.js .ts .tsx코드를 통해 생성하는 애플 아이콘

4.2 Open Graph 및 Twitter 이미지

이름유형설명
opengraph-image.jpg .jpeg .png .gifOG 이미지 정적 파일
opengraph-image.js .ts .tsx코드로 생성하는 OG 이미지
twitter-image.jpg .jpeg .png .gif트위터 카드 이미지 정적 파일
twitter-image.js .ts .tsx코드로 생성하는 트위터 이미지

4.3 SEO 관련 파일

이름유형설명
sitemap.xml정적 사이트맵 파일
sitemap.js .ts코드로 생성하는 사이트맵
robots.txt정적 robots 규칙 파일
robots.js .ts코드로 생성하는 robots 설정

5. 프로젝트 구조화 (Organizing your project)

Next.js는 프로젝트 구조에 대해 강한 규칙을 강요하지 않습니다. 다만, 몇 가지 기능을 제공하여 팀에 맞는 구조를 만들 수 있도록 돕습니다.

5.1 컴포넌트 계층 구조 (Component hierarchy)

특수 파일로 정의된 컴포넌트들은 다음 순서로 중첩되어 렌더링됩니다.

  1. layout.js
  2. template.js
  3. error.js (에러 경계)
  4. loading.js (Suspense 경계)
  5. not-found.js (“찾을 수 없음” UI)
  6. page.js 또는 더 안쪽의 layout.js

중첩 라우트에서는 부모 세그먼트의 컴포넌트 안에 자식 세그먼트의 컴포넌트가 재귀적으로 중첩됩니다.

5.2 Colocation

  • app 디렉터리에서 폴더 구조는 라우트 구조를 정의합니다.
  • page.js 또는 route.js가 있는 세그먼트만 실제로 공개 라우트가 됩니다.
  • page.js / route.js 파일에서 반환하는 콘텐츠만 클라이언트로 전송되므로, 같은 폴더 안에 다른 프로젝트 파일을 함께 두더라도 라우트로 노출되지 않습니다.
  • 즉, app 디렉터리 안에 컴포넌트, 유틸, 훅 등을 함께 “colocate”해도 안전합니다.
  • 원한다면 프로젝트 파일을 app 밖에 두고 라우팅만 app 안에 둘 수도 있습니다.

5.3 Private 폴더

  • 폴더 이름 앞에 밑줄을 붙이면 _folderName 형태의 private 폴더가 됩니다.
  • 라우팅에서 완전히 제외되며, 구현 세부 사항을 모아두는 용도로 사용합니다.
  • 활용 예:
    • UI 로직과 라우팅 로직을 분리
    • 프로젝트 전반에서 내부 파일을 일관된 패턴으로 정리
    • 코드 에디터에서 파일을 그룹화
    • 향후 Next.js 특별 파일 이름과의 충돌 가능성 줄이기

추가 팁:

  • app 밖의 파일에도 같은 언더스코어 패턴을 사용해 “private” 의미를 담을 수 있습니다.
  • URL에서 언더스코어로 시작하는 세그먼트를 사용하고 싶다면, 폴더명을 %5FfolderName처럼 URL 인코딩된 형태로 사용할 수 있습니다.
  • Private 폴더를 사용하지 않을 경우, Next.js의 특수 파일 이름 규칙을 알고 있는 것이 좋습니다.

5.4 Route 그룹

  • (folderName) 형식의 폴더는 URL에서 생략됩니다.
  • 주요 용도:
    • 마케팅, 관리자, 대시보드 등 섹션/의도/팀별로 라우트를 조직화
    • 같은 URL 계층에서 여러 개의 중첩 레이아웃을 만들기
    • 여러 root layout을 구성하거나, 특정 라우트 집합에만 레이아웃을 적용하기

5.5 src 폴더

  • 애플리케이션 코드를 src 하위로 모을 수 있습니다 (src/app, src/components 등).
  • 루트에는 설정 파일들만 두고, 실제 코드들은 src 안에 두어 구조를 명확히 분리하는 패턴입니다.

6. 프로젝트 구조 예시 (Examples)

문서에서는 대표적인 구조 전략을 몇 가지 예로 보여 줍니다. 핵심은 팀에 맞는 전략을 하나 정해서 일관되게 유지하는 것입니다.

예시에서 사용하는 components, lib 등의 폴더 이름은 Next.js에서 특별한 의미를 갖지 않습니다. 필요에 따라 ui, utils, hooks, styles 등 다른 이름을 사용해도 됩니다.

6.1 app 밖에 프로젝트 파일 두기

  • app 디렉터리는 라우팅 전용으로 사용합니다.
  • 공통 컴포넌트, 유틸, 스타일 등은 루트의 별도 폴더에 둡니다.
app/
  layout.tsx
  page.tsx
components/
  Button.tsx
lib/
  api.ts
styles/
  globals.css

6.2 app 안의 상위 폴더에 두기

  • app 디렉터리 내부에 components, lib 등 공용 폴더를 만들어 둡니다.
app/
  layout.tsx
  page.tsx
  components/
    Button.tsx
  lib/
    api.ts

6.3 기능 또는 라우트 단위로 나누기

  • 전역적으로 공유되는 코드만 루트에 두고,
    특정 라우트에서만 쓰이는 코드는 해당 세그먼트 아래에 함께 둡니다.
app/
  layout.tsx
  page.tsx
  dashboard/
    layout.tsx
    page.tsx
    _components/
      Charts.tsx
    _lib/
      fetchDashboard.ts

6.4 URL을 바꾸지 않고 라우트 구조만 정리하기

  • (marketing), (shop) 같은 route group을 사용하여 URL에는 영향을 주지 않으면서 관련 라우트를 묶습니다.
  • 각 그룹 안에 layout.tsx를 두어 서로 다른 레이아웃을 적용할 수 있습니다.

6.5 특정 세그먼트만 레이아웃에 참여시키기

  • 예를 들어 (shop) 그룹 안에 account, cart 라우트만 넣고, checkout은 그룹 밖에 두면,
    account/cart만 공통 레이아웃을 공유하고 checkout은 다른 레이아웃을 사용할 수 있습니다.

6.6 특정 라우트에만 로딩 스켈레톤 적용하기

  • /(overview) 같은 그룹을 만들고, 그 안에 loading.tsxpage.tsx를 두면,
    해당 그룹에 속한 라우트에만 loading.tsx가 적용됩니다.

6.7 여러 개의 루트 레이아웃 만들기

  • 최상위 layout.js를 제거하고, 각 route group 안에 layout.js를 두면,
    (marketing), (shop) 등이 각각 독립적인 root layout을 갖게 됩니다.
  • 이때 각 root layout에는 <html><body> 태그를 직접 포함해야 합니다.