동적·중첩 라우팅 — [slug]·(group)·[...all] 정리
폴더 이름의 대괄호·소괄호가 URL 을 결정한다. 4가지 패턴이면 끝.
3·4편에서 정적 경로(/about·/blog) 를 만드는 법은 익혔다. 그런데 실전 사이트는 정적만으론 부족하다. 블로그 글마다 다른 URL(/blog/hello-world·/blog/next-tips), 사용자 프로필(/users/123), 문서 사이트의 무한 중첩(/docs/a/b/c) — 다 동적이다.
Next.js 는 이걸 풀기 위해 폴더 이름의 트릭 4가지를 제공한다. [slug]·(group)·[...all]·[[slug]]. 이번 편에서 하나씩 손에 익힌다.
1. [slug] — 동적 세그먼트 한 단어
가장 자주 쓰는 패턴. 폴더 이름을 대괄호로 감싸면 그 자리에 어떤 값이 와도 매칭된다.
이 한 파일로 /blog/hello·/blog/anything·/blog/2026-04-22 가 모두 같은 페이지를 그린다. 페이지 안에선 params 로 그 값을 받는다.
Next 15 부터 params 가 Promise 라는 게 큰 변화. 14 까지는 동기였는데 15 부터 비동기로 바뀌어 await 가 필요하다. 마이그레이션 가이드 (23편)에서 자세히.
app/users/[userId]/posts/[postId]/page.tsx 처럼 중첩 가능. params 객체에 둘 다 담겨 온다: { userId, postId }.
2. (group) — URL 에 영향 X, 폴더만 묶음
괄호 폴더는 URL 에 안 나타난다. 코드 구조만 정리하는 용도.
URL 만 보면 마케팅 페이지와 앱 페이지가 같은 레벨인데, 폴더 분리로 서로 다른 layout 을 줄 수 있다. 마케팅은 큰 헤더·풋터, 앱은 사이드바·작은 헤더 — 같은 사이트에 두 가지 UI 가 공존할 때 필수 패턴.
(marketing)/dashboard/page.tsx 와 (app)/dashboard/page.tsx 가 동시에 있으면 충돌. 각 URL 은 정확히 한 곳에서만 만들어야.
3. [...all] — Catch-all 세그먼트
대괄호 안에 점 3개. "나머지 경로 통째로 받아라" 라는 뜻.
이 하나로 다음이 모두 매칭된다:
/docs/intro→slug = ['intro']/docs/guide/installation→slug = ['guide', 'installation']/docs/api/v2/users→slug = ['api', 'v2', 'users']
문서 사이트·위키처럼 깊이를 미리 알 수 없는 경로에 쓴다. 페이지 안에선 slug 가 배열로 들어온다.
단, /docs (slug 가 없는 경우) 는 이걸로 안 잡힌다. 그 경우엔 옵셔널 catch-all 이 필요.
4. [[...all]] — Optional Catch-all
대괄호를 한 번 더 감싸면 — 없어도 매칭됨.
이건 /docs · /docs/intro · /docs/guide/installation 모두 같은 페이지로 잡는다. /docs 일 땐 slug 가 undefined, 깊은 경로면 배열.
실용도가 가장 높은 케이스 — 문서 사이트 + 인덱스 페이지를 한 파일로. slug 가 없으면 "전체 목차", 있으면 "해당 문서" 식으로 분기.
5. 네 가지를 한 표로
| 패턴 | 매칭 | params 모양 | 대표 사용처 |
|---|---|---|---|
[slug] | 정확히 한 세그먼트 | string | 블로그 글·상품 상세 |
(group) | URL 에 미반영 | N/A | layout 분리 (마케팅/앱) |
[...slug] | 1개 이상 세그먼트 | string[] | 문서 사이트 (인덱스 별도) |
[[...slug]] | 0개 이상 세그먼트 | string[] | undefined | 문서 사이트 (인덱스 같이) |
실전 비율 — [slug] 70% · (group) 20% · catch-all 둘 합쳐 10%. 처음엔 [slug] 만 익혀도 충분.
요약 — 5편 좌표
여기까지 정리. Next.js App Router 는 폴더 이름으로 라우팅을 결정한다 — 대괄호 동적, 소괄호 그룹, 대괄호 점3개 catch-all, 대괄호 한 번 더 옵셔널. 페이지 안에선 params (Next 15 부터 Promise) 로 동적 값을 받는다. 같은 URL 이 둘 이상 폴더에 매칭되면 충돌이라 주의. 다음 편에선 가장 큰 개념 — Server Component vs Client Component — 의 차이를 본다.
다음 편 예고 — Server Component vs Client Component
두 컴포넌트 모델의 결정적 차이와 사용 기준. 'use client' 의 의미. 6편.