Routing 파일
각 Route Segment별로 아래와 같은 파일들을 정의할 수 있다.
파일 이름 | 확장자 | 역할 설명 |
---|---|---|
layout | .js , .jsx , .tsx | 공통 UI 레이아웃 정의. 현재 디렉토리와 하위 경로에 공통 적용됨. 헤더, 사이드바, 레이아웃 컴포넌트 정의에 사용됨 |
page | .js , .jsx , .tsx | 해당 경로의 실제 페이지. 사용자 요청 시 이 파일이 SSR되어 보여짐 |
loading | .js , .jsx , .tsx | Suspense 기반의 로딩 UI. 해당 경로의 데이터를 fetch하는 동안 보여짐 |
not-found | .js , .jsx , .tsx | 404 UI. 페이지를 찾을 수 없을 때 렌더링됨 |
error | .js , .jsx , .tsx | 경로별 에러 UI. 이 경로에서 발생한 에러를 잡아 렌더링함 |
global-error | .js , .jsx , .tsx | 앱 전체에서 잡히지 않은 에러 처리 UI. 보통 루트 디렉토리 app/ 하위에 위치 |
route | .js , .ts | API Route. 서버에서 실행되는 핸들러 함수 (GET , POST 등). app/api/**/route.ts 식으로 사용 |
template | .js , .jsx , .tsx | 재사용 안되는 개별 레이아웃. 페이지 간 이동할 때 새로 마운트되며 상태가 초기화됨 |
default | .js , .jsx , .tsx | 병렬 라우트의 기본 fallback. 조건에 따라 보여줄 분기 UI 중 기본값 역할 |
layout
: 공통 UI 구조page
: 페이지 진입점loading
: fetch 중 로딩 상태not-found
: 404 처리error
: 해당 경로 에러 처리global-error
: 앱 전체 에러 처리route
: API 요청 처리template
: 상태 초기화가 필요한 레이아웃default
: 병렬 라우트의 기본 대체 UI
Route Segment의 파일들은 nested된 하위 Route Segement에도 영향을 준다.
layout.tsx
: 공통 레이아웃을 정의한다
layout.tsx
파일은 그 디렉토리와 하위 디렉토리의 모든 페이지에 대해 공통적으로 적용되는 UI 틀(Layout) 을 정의한다. 일반적으로 Header, Footer, Sidebar 등의 공통 구조를 포함시킨다.
-
예시:
/app/layout.tsx → 사이트 전체 공통 레이아웃 /app/blog/layout.tsx → 블로그 페이지 전용 레이아웃
- 예제: 최상위
app/layout.tsx
// app/layout.tsx export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="ko"> <body> <header>공통 헤더</header> <main>{children}</main> <footer>공통 푸터</footer> </body> </html> ); }
- 예제: 블로그 전용 레이아웃
app/blog/layout.tsx
// app/blog/layout.tsx export default function BlogLayout({ children }: { children: React.ReactNode }) { return ( <section style={{ display: "flex" }}> <aside style={{ width: 200, background: "#f3f3f3" }}>블로그 사이드바</aside> <div style={{ flex: 1 }}>{children}</div> </section> ); }
-
특징:
children
을 반드시 props로 받아야 한다. 이children
자리에 해당 라우트의page.tsx
가 삽입된다.- layout은 클라이언트와 서버 양쪽 모두에서 사용할 수 있으며, React Server Component로 작성할 수 있다.
- 상위
layout.tsx
는 하위layout.tsx
와 중첩되며, 바깥쪽부터 안쪽으로 감싸지는 구조다.
page.tsx
: 실제 페이지를 정의한다
page.tsx
파일은 특정 URL에 대응되는 실제 렌더링 대상 페이지를 정의한다. 사용자가 브라우저에서 어떤 경로로 접근할 때, 해당 경로에 일치하는 page.tsx
파일이 실행되어 React 컴포넌트가 클라이언트에게 렌더링된다.
-
예시:
/app/about/page.tsx → https://도메인/about /app/blog/[slug]/page.tsx → https://도메인/blog/abc
- 예제:
/blog/page.tsx
// app/blog/page.tsx export default function BlogPage() { return ( <main> <h1>블로그 메인</h1> <p>최근 게시글 목록을 보여줍니다.</p> </main> ); }
- 예제:
/blog/[slug]/page.tsx
// app/blog/[slug]/page.tsx type PageProps = { params: { slug: string }; }; export default function BlogDetailPage({ params }: PageProps) { return ( <main> <h1>{decodeURIComponent(params.slug)} 게시글</h1> <p>이곳에 게시글 내용을 렌더링합니다.</p> </main> ); }
-
특징:
export default
로 React 컴포넌트를 반환해야 한다.params
,searchParams
등 라우팅 정보를 props로 받을 수 있다.- 반드시
page.tsx
파일명이어야 한다.about.tsx
처럼 커스텀 파일명은 인식되지 않는다.
layout.tsx
와 page.tsx
의 동작 관계
- 레이아웃은 한번 렌더링되면 라우트 전환 간에도 유지된다.
- 반면 페이지는 라우트 변경 시마다 다시 렌더링된다.
- 따라서 무거운 상태나 네비게이션 요소 등은
layout.tsx
에 넣고, 동적으로 바뀌는 콘텐츠는page.tsx
에 배치하는 것이 일반적이다.
/app
├── layout.tsx → 전체 앱 레이아웃 (Header, Footer 포함)
├── page.tsx → / 홈 페이지
├── about
│ └── page.tsx → /about 페이지
└── blog
├── layout.tsx → 블로그 영역 전용 레이아웃 (ex. 좌측 사이드바 포함)
├── page.tsx → /blog 페이지
└── [slug]
└── page.tsx → /blog/[slug] 상세 페이지
위 구조에서 /blog/post-1
으로 접근하면 다음 순서대로 컴포넌트가 계층적으로 렌더링된다:
app/layout.tsx
└── blog/layout.tsx
└── blog/[slug]/page.tsx
기타 Routing 파일
loading.tsx
: 로딩 상태 UI를 정의한다
loading.tsx
파일은 해당 경로의 데이터를 가져오는 동안 보여줄 로딩 스켈레톤 컴포넌트를 정의한다. Next.js는 이 파일을 자동으로 React.Suspense
의 fallback처럼 처리한다.
-
예시:
/app/blog/loading.tsx → /blog 경로의 데이터를 fetch하는 동안 로딩 UI 표시
-
예제:
// app/blog/loading.tsx export default function Loading() { return <p>잠시만 기다려 주세요... 블로그 데이터를 불러오는 중입니다.</p>; }
-
특징:
- 서버 컴포넌트 또는 클라이언트 컴포넌트로 작성 가능하다.
- 해당 경로에서 데이터를 fetch하거나 서버에서 응답이 늦는 경우 자동으로 보여진다.
not-found.tsx
: 404 Not Found 페이지 정의
not-found.tsx
는 경로에 해당하는 페이지가 없을 때 렌더링되는 UI다. Next.js에서 제공하는 notFound()
함수를 호출하면 이 UI로 리다이렉션된다.
-
예시:
/app/blog/not-found.tsx → 블로그에서 존재하지 않는 slug 접근 시
-
예제:
// app/blog/not-found.tsx export default function BlogNotFound() { return <h1>존재하지 않는 블로그 글입니다.</h1>; }
-
예제: 페이지에서 수동 호출
import { notFound } from "next/navigation"; export default function BlogPost({ params }) { const post = getPostBySlug(params.slug); if (!post) return notFound(); return <div>{post.title}</div>; }
error.tsx
: 경로 단위 에러 UI
error.tsx
는 해당 경로 내에서 발생한 런타임 에러를 잡아주는 에러 바운더리 역할을 한다. 특정 디렉토리 내부에서만 적용된다.
-
예시:
/app/blog/error.tsx → 블로그 관련 페이지에서만 발생한 에러를 처리
-
예제:
// app/blog/error.tsx "use client"; export default function BlogError({ error }: { error: Error }) { return ( <div> <h2>블로그를 불러오는 중 오류가 발생했습니다.</h2> <p>{error.message}</p> </div> ); }
-
특징:
- 반드시
"use client"
지시어가 필요하다. - error 객체를 prop으로 받을 수 있다.
- 반드시
global-error.tsx
: 앱 전역 에러 처리
global-error.tsx
는 루트 디렉토리에 위치하며, error.tsx
에서 처리되지 않은 에러를 처리하는 전역 에러 바운더리이다.
-
예시:
/app/global-error.tsx
-
예제:
// app/global-error.tsx "use client"; export default function GlobalError({ error }: { error: Error }) { return ( <html> <body> <h1>앱 전역 오류 발생</h1> <p>{error.message}</p> </body> </html> ); }
template.tsx
: 새로 마운트되는 일회성 레이아웃
template.tsx
는 layout.tsx
와 유사하지만, 페이지 간 이동 시 상태를 유지하지 않고 새로 마운트된다. 로그인 페이지, 모달처럼 독립적인 컨텍스트가 필요한 경우에 사용된다.
-
예시:
/app/(auth)/login/template.tsx
-
예제:
// app/(auth)/login/template.tsx export default function LoginTemplate({ children }: { children: React.ReactNode }) { return <div className="login-layout">{children}</div>; }
-
특징:
- 같은 라우트라도 이동할 때마다 다시 렌더링된다 (즉, 상태 초기화).
- layout과 달리 상태가 유지되지 않는다.
default.tsx
: 병렬 라우트의 fallback UI
default.tsx
는 병렬 라우트에서 선택적으로 보여질 분기 UI 중 기본값을 정의하는 데 사용된다. route segment를 선택적으로 보여줘야 할 때 유용하다.
-
예시:
/app/(tabs)/@details/default.tsx → 기본으로 보여질 탭
-
예제:
// app/(tabs)/@details/default.tsx export default function DetailsDefault() { return <div>아무 탭도 선택되지 않았습니다.</div>; }
예시 폴더구조
app/
├── layout.tsx # 전체 앱 공통 레이아웃
├── page.tsx # 홈 (/)
├── loading.tsx # 홈 페이지 Suspense 로딩 UI
├── global-error.tsx # 앱 전체 에러 처리
├── about/
│ ├── page.tsx # /about 페이지
│ ├── loading.tsx # /about 로딩 UI
│ └── error.tsx # /about 에러 처리
├── blog/
│ ├── layout.tsx # /blog 공통 레이아웃 (ex. 사이드바)
│ ├── page.tsx # /blog 메인
│ ├── loading.tsx # /blog 로딩 UI
│ ├── error.tsx # /blog 전용 에러 UI
│ └── not-found.tsx # /blog 404 처리
│ └── [slug]/ # /blog/:slug
│ ├── page.tsx # 블로그 게시글 상세
│ └── not-found.tsx # 존재하지 않는 게시글 처리
├── (auth)/ # 병렬 라우트 그룹 (예: 로그인/회원가입 등)
│ └── login/
│ ├── page.tsx # /login
│ ├── template.tsx # 로그인 시 상태 초기화용 레이아웃
│ └── error.tsx # 로그인 에러 처리
├── (tabs)/ # 병렬 라우트 예시
│ ├── layout.tsx
│ ├── @details/
│ │ ├── page.tsx # /tabs/@details 탭 내용
│ │ └── default.tsx # 아무 탭 선택 안 했을 때 fallback
│ └── @settings/
│ └── page.tsx # /tabs/@settings 탭 내용
<br />