폴더로 정의하는 라우트와 동적·중첩·그룹 경로.
App Router 라우팅
App Router에서 라우팅은 코드가 아니라 폴더 구조로 결정됩니다. 폴더를 만들면 경로가 생기고, 그 안의 page.tsx 가 화면이 됩니다. 이번 레슨에서는 정적 경로부터 동적·중첩·그룹 경로, 그리고 페이지 사이를 이동하는 방법까지 살펴봅니다.
학습 목표
- 폴더 = 라우트라는 규칙을 이해한다.
- 동적 세그먼트
[slug]로 가변 경로를 만든다. - 중첩 라우트와 라우트 그룹
(folder)을 구분한다. Link,useRouter,params로 이동하고 값을 읽는다.
폴더가 곧 라우트
폴더 이름이 URL이 되고, 그 안의 page.tsx 가 페이지가 됩니다.
app/
├── page.tsx → /
├── dashboard/
│ ├── page.tsx → /dashboard
│ └── settings/page.tsx → /dashboard/settings
└── shop/
└── cart/page.tsx → /shop/cart
page.tsx 가 없는 폴더는 URL을 만들지 않습니다. 폴더는 구조를 나누는 용도로만 쓸 수도 있습니다.
동적 세그먼트 [slug]
대괄호로 폴더 이름을 감싸면 가변 경로가 됩니다. /blog/hello, /blog/world 처럼 어떤 값이 와도 같은 페이지가 처리합니다.
app/
└── blog/
└── [slug]/page.tsx → /blog/무엇이든
페이지는 params 를 통해 그 값을 받습니다. App Router 최신 버전에서 params 는 Promise 이므로 await 합니다.
// app/blog/[slug]/page.tsx
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
return <h1>글: {slug}</h1>;
}
여러 세그먼트를 한꺼번에 받고 싶으면 [...slug](catch-all)를 씁니다. /docs/a/b/c 가 ['a', 'b', 'c'] 로 들어옵니다.
중첩과 라우트 그룹
폴더 안에 폴더를 넣으면 경로가 그대로 중첩됩니다. 반면 소괄호로 감싼 폴더 (group) 는 URL에 나타나지 않습니다. 코드를 묶어 정리하거나, 레이아웃을 다르게 적용할 때 유용합니다.
app/
├── (marketing)/
│ ├── layout.tsx → 마케팅 전용 레이아웃
│ └── about/page.tsx → /about ( (marketing) 은 URL에 없음)
└── (shop)/
├── layout.tsx → 쇼핑 전용 레이아웃
└── products/page.tsx → /products
💡 TIP — 같은 URL 깊이지만 레이아웃을 나누고 싶을 때 라우트 그룹이 빛납니다. 예를 들어 로그인 화면과 본 화면의 레이아웃을 분리할 수 있습니다.
병렬·인터셉트 라우트 (맛보기)
조금 더 고급 기능도 있습니다. 지금은 "이런 게 있다" 정도만 알아 두면 됩니다.
| 표기 | 이름 | 쓰임 |
|---|---|---|
@folder | 병렬 라우트 | 한 레이아웃에 여러 슬롯을 동시에 렌더 |
(.)folder | 인터셉트 라우트 | 모달처럼 다른 경로를 가로채 겹쳐 표시 |
페이지 이동하기
화면 간 이동은 <a> 대신 next/link 의 Link 를 씁니다. 페이지 전체를 새로고침하지 않고 부드럽게 전환됩니다.
import Link from 'next/link';
export default function Nav() {
return (
<nav>
<Link href="/">홈</Link>
<Link href="/blog/hello">첫 글</Link>
</nav>
);
}
코드 안에서 이동하거나 검색 파라미터를 읽으려면 클라이언트 컴포넌트에서 훅을 씁니다.
'use client';
import { useRouter, useSearchParams } from 'next/navigation';
export default function SearchButton() {
const router = useRouter();
const params = useSearchParams();
return (
<button onClick={() => router.push(`/search?q=${params.get('q') ?? ''}`)}>
검색
</button>
);
}
⚠️ 주의 —
useRouter는next/navigation에서 가져옵니다. 예전 Pages Router의next/router와 헷갈리지 마세요.
요약
- 폴더 구조가 그대로 URL이 되고,
page.tsx가 화면이 된다. [slug]는 동적 세그먼트이며params(Promise)로 값을 받는다.(group)은 URL에 드러나지 않고 코드/레이아웃을 묶는다.- 이동은
Link, 코드 내 이동·파라미터 읽기는useRouter/useSearchParams로 한다.
연습문제
/products/[id]페이지를 만들어id를 화면에 출력해 보세요.- 라우트 그룹
(auth)를 만들고 그 안에/login,/signup페이지를 두세요. URL에auth가 나타나지 않는지 확인하세요. - 네비게이션 바를 만들고
Link로 세 페이지를 연결해 보세요. - catch-all 라우트
[...path]가 어떤 경우에 유용할지 한 가지 예를 적어 보세요.
힌트 — 동적 페이지에서
const { id } = await params;로 값을 꺼냅니다. 라우트 그룹 폴더 이름은 반드시 소괄호로 감싸야 합니다.
💡 연습문제 풀이
불러오는 중…
댓글 0
“Next.js” 강좌에 대한 댓글입니다.