app/의 폴더가 주소를 만든다
App Router에서는 폴더 하나가 URL의 한 구간을 나타내. 다만 폴더만 만든다고 외부에 주소가 생기지는 않아. 그 안에 page.tsx가 있어야 비로소 방문할 수 있는 라우트가 돼. 그래서 app/blog/[slug]/page.tsx는 /blog/:slug에 대응하고, 폴더를 중첩한 깊이가 그대로 주소의 깊이가 돼.
| 파일 | 주소 |
|---|---|
app/page.tsx | / |
app/about/page.tsx | /about |
app/blog/page.tsx | /blog |
app/blog/[slug]/page.tsx | /blog/:slug |
app/dashboard/settings/page.tsx | /dashboard/settings |
공개 여부를 결정하는 파일은 page.tsx야
같은 폴더에 도우미 함수나 작은 컴포넌트를 함께 둬도 그 파일들이 별도 URL로 노출되지는 않아. 프레임워크는 필요한 모듈을 불러오지만, page.tsx가 없는 폴더는 공개 라우트로 취급하지 않거든. 관련 코드를 화면 가까이에 놓으면서도 주소 체계를 흐리지 않을 수 있는 이유야.
특수 파일은 라우트의 행동을 나눠 맡아
| 파일 | 맡는 일 |
|---|---|
page.tsx | 해당 구간의 화면을 공개해. |
layout.tsx | 하위 화면을 감싸고 이동 뒤에도 유지돼. |
loading.tsx | 해당 구간의 Suspense 대체 화면이 돼. |
error.tsx | 오류 경계를 만들며 클라이언트 컴포넌트여야 해. |
not-found.tsx | notFound()가 실행됐을 때 보일 화면이야. |
template.tsx | 레이아웃과 비슷하지만 이동할 때마다 새로 마운트돼. |
default.tsx | 직접 방문한 병렬 라우트 슬롯의 대체 화면이야. |
route.ts | HTTP 엔드포인트를 만들며 같은 폴더의 page.tsx와 공존할 수 없어. |
새 URL을 만들 때 먼저 공개 주소를 적고, 그다음 같은 모양의 폴더 트리를 만들어. 화면과 가까운 도우미는 그 폴더에 함께 두되 page.tsx만 공개 경계를 연다는 규칙을 유지해. 코드 조직용 폴더와 주소용 폴더가 헷갈리면 괄호 라우트 그룹을 써서 의도를 드러내. 파일 기반 라우팅이 설계를 대신해 주지는 않아. 폴더를 깊게 나누기 쉽다는 이유로 제품의 정보 구조까지 깊게 만들면 사용자가 긴 URL과 복잡한 내비게이션을 떠안아. 먼저 사람이 이해할 주소 체계를 정하고 파일 트리가 그 결과를 상속하게 해야 해.
예상 URL 목록과 실제 빌드 라우트 목록을 비교하고, 공개할 생각이 없는 같은 위치의 파일을 주소로 직접 요청해 봐. page.tsx와 route.ts를 같은 구간에 두었을 때 빌드가 어떻게 거부하는지도 확인하면 파일 관례가 단순 이름 규칙이 아니라 충돌 방지 계약임을 알 수 있어.