Next.js 라우팅의 기본 개념
Next.js의 가장 큰 특징 중 하나는 파일 시스템 기반 라우팅(File-system based routing)이다.
이 방식은 React의 SPA(Single Page Application)에서 흔히 사용되는 React Router와 같은 별도의 라우팅 라이브러리가 필요 없다는 큰 장점이 있다.
Next.js는 프로젝트의 디렉토리 구조와 파일명을 기반으로 자동으로 라우팅을 구성한다.
파일 시스템 기반 라우팅이란 간단히 말해 폴더와 파일의 구조가 곧 웹 애플리케이션의 URL 경로(path)가 되는 방식이다.
예를 들어, /pages/about.tsx 파일은 example.com/about URL로 접근할 수 있다.
이렇게 직관적인 구조는 프로젝트의 구조를 이해하기 쉽게 만들고, 라우팅 설정에 드는 시간과 노력을 크게 줄여주는 것 같다.
Next.js의 라우팅 시스템은 이런 직관적인 파일 구조를 통해 개발자가 복잡한 라우팅 로직을 작성하지 않고도 효율적으로 다중 페이지 애플리케이션을 구축할 수 있게 해준다!!!
예를 들어보겠다. => /about 경로를 만들어보자.
Next.js 13+ App Router에서는 폴더명 (예시에서는 about 폴더)은 실제 URL 경로가 된다.
그리고 그 폴더 안에 있는 page.tsx가 해당 경로의 페이지 컴포넌트가 된다고 보면된다.
이렇게 src/app에 about폴더를 만들고 page.tsx를 위와 같이 정의해주면
위와 같이 /about 경로에 해당 컴포넌트가 보여지는 것을 볼 수 있다!!!
관련해서는 밑에서 더 자세하게 설명하겠다.
Pages Router vs App Router
Next.js의 라우팅 시스템은 크게 두 가지로 나뉜다. 바로 Pages Router와 App Router이다.
이 두 라우터의 차이점을 이해하는 것은 Next.js 애플리케이션을 구축할 때 매우 중요하다.
- Pages Router는 Next.js의 전통적인 라우팅 시스템으로, /pages 디렉토리를 기반으로 한다. 이 방식에서는 /pages 폴더 내에 위치한 모든 파일이 해당 경로의 라우트가 된다. 예를 들어, /pages/products/index.tsx는 /products 경로에 매핑되고, /pages/products/[id].tsx는 /products/1, /products/2 등의 동적 경로에 매핑된다.
- App Router는 Next.js 13 버전부터 도입된 새로운 라우팅 시스템으로, /app 디렉토리를 기반으로 한다. App Router는 React 서버 컴포넌트를 완전히 지원하고, 중첩 레이아웃, 로딩 상태, 에러 처리 등 더 많은 기능을 제공한다. App Router에서는 특수 파일명을 사용하여 라우트의 다양한 측면을 정의한다.
App Router를 사용하면 /app/dashboard/page.tsx와 같은 형태로 페이지를 정의한다. 여기서 page.tsx는 특수 파일명으로, 해당 경로의 UI를 정의한다. 그 외에도 layout.tsx, loading.tsx, error.tsx 등의 특수 파일명을 사용하여 각각 레이아웃, 로딩 상태, 에러 화면 등을 정의할 수 있다.
App Router는 Pages Router보다 더 강력하고 유연한 기능을 제공하지만, Pages Router도 여전히 지원되며 두 방식을 함께 사용할 수도 있다. 다만 새로운 프로젝트를 시작한다면 App Router를 사용하는 것이 권장된다.
App Router의 파일 시스템 기반 라우팅
App Router에서는 /app 디렉토리 내의 폴더가 라우트 세그먼트에 매핑된다.
각 폴더 내에는 특수 파일들을 사용하여 해당 라우트의 UI를 정의한다.
가장 중요한 특수 파일은 page.tsx로, 이 파일이 해당 라우트의 UI를 정의하고 해당 경로를 공개적으로 접근 가능하게 만든다.
// app/dashboard/page.tsx
export default function DashboardPage() {
return (
<div>
<h1>대시보드</h1>
<p>이 페이지는 /dashboard URL로 접근됩니다.</p>
</div>
);
}
위 코드는 /dashboard URL에 접근할 때 보여질 페이지를 정의한다.
page.tsx 파일은 React 컴포넌트를 default export로 내보내며, 이 컴포넌트가 해당 라우트의 UI가 된다!!!
App Router에서는 다음과 같은 특수 파일들을 사용할 수 있다:
- page.tsx: 라우트의 UI를 정의하고 해당 라우트를 공개적으로 접근 가능하게 만든다.
- layout.tsx: 하위 라우트들을 위한 공유 레이아웃을 정의한다.
- loading.tsx: 페이지 로딩 중에 보여질 로딩 UI를 정의한다.
- error.tsx: 에러 발생 시 보여질 에러 UI를 정의한다.
- not-found.tsx: 존재하지 않는 라우트에 접근했을 때 보여질 404 페이지를 정의한다.
이러한 특수 파일들을 통해 App Router는 라우팅뿐만 아니라 다양한 UI 상태를 선언적으로 처리할 수 있도록 해준다!!!!
라우트 그룹과 레이아웃
Next.js의 App Router에서는 라우트 그룹과 레이아웃을 통해 보다 체계적인 라우팅 구조를 구성할 수 있다.
**라우트 그룹(Route Groups)**은 폴더명을 괄호로 감싸서 정의한다 - (folderName)
라우트 그룹은 URL 경로에 영향을 주지 않으면서 라우트를 논리적으로 그룹화할 수 있게 해준다!
app/
├── (marketing)/
│ ├── about/
│ │ └── page.tsx // /about
│ └── blog/
│ └── page.tsx // /blog
└── (shop)/
├── products/
│ └── page.tsx // /products
└── cart/
└── page.tsx // /cart
**레이아웃(Layouts)**은 layout.tsx 파일을 통해 정의되며, 여러 페이지 간에 공유되는 UI를 제공한다.
레이아웃은 중첩될 수 있어 상위 레이아웃 안에 하위 레이아웃을 포함할 수 있다.
// app/layout.tsx (루트 레이아웃)
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ko">
<body>
<header>내 웹사이트</header>
<main>{children}</main>
<footer>© 2025</footer>
</body>
</html>
);
}
// app/dashboard/layout.tsx (대시보드 레이아웃)
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div>
<nav>
<ul>
<li>홈</li>
<li>프로필</li>
<li>설정</li>
</ul>
</nav>
<div className="dashboard-content">{children}</div>
</div>
);
}
- 위 코드에서 app/layout.tsx는 모든 페이지에 적용되는 루트 레이아웃을 정의하고,
- app/dashboard/layout.tsx는 /dashboard 경로와 그 하위 경로에만 적용되는 레이아웃을 정의한다.
이렇게 중첩된 레이아웃을 통해 특정 섹션에만 적용되는 UI를 쉽게 구현할 수 있다!
동적 라우팅 구현하기
Next.js의 동적 라우팅은 URL 경로의 일부를 변수로 사용할 수 있게 해주는 기능이다.
이는 블로그 포스트, 제품 상세 페이지 등 비슷한 구조를 가지지만 다른 콘텐츠를 보여주는 페이지들을 효율적으로 구현할 수 있게 해준다.
App Router에서는 폴더명을 대괄호로 감싸서 동적 라우트를 정의한다 - [folderName].
이렇게 정의된 동적 세그먼트는 params 객체를 통해 접근할 수 있다.
// app/products/[id]/page.tsx
export default function ProductPage({
params,
}: {
params: { id: string };
}) {
return (
<div>
<h1>제품 상세 페이지</h1>
<p>제품 ID: {params.id}</p>
</div>
);
}
위 코드는 /products/1, /products/2 등의 URL에 대응하는 페이지를 정의한다.
URL에서 [id] 부분에 해당하는 값이 params.id로 전달된다.
더 복잡한 동적 라우팅도 구현할 수 있다.
예를 들어, 여러 세그먼트를 동적으로 처리하려면 [...folderName] 문법을 사용할 수 있다(캐치올 라우트라고도 함).
// app/blog/[...slug]/page.tsx
export default function BlogPostPage({
params,
}: {
params: { slug: string[] };
}) {
return (
<div>
<h1>블로그 포스트</h1>
<p>경로: {params.slug.join('/')}</p>
</div>
);
}
위 코드는 /blog/2023/01/my-post 같은 URL에 대응하며, params.slug는 ['2023', '01', 'my-post'] 배열이 된다!!!
선택적 캐치올 라우트를 구현하려면 [[...folderName]] 문법을 사용할 수 있다. 이는 기본 경로와 동적 경로 모두에 대응한다!
// app/shop/[[...categories]]/page.tsx
export default function ShopPage({
params,
}: {
params: { categories?: string[] };
}) {
return (
<div>
<h1>상점</h1>
{params.categories ? (
<p>카테고리: {params.categories.join('/')}</p>
) : (
<p>모든 제품</p>
)}
</div>
);
}
위 코드는 /shop, /shop/clothing, /shop/clothing/shirts 등의 URL에 모두 대응한다!!!
'Next.js' 카테고리의 다른 글
[Next.js] ❗️입문자 주목❗️ TypeScript로 구현하는 로그인 시스템 튜토리얼 (0) | 2025.03.14 |
---|---|
[Next.js] App Router vs Pages Router (4) | 2025.03.13 |
[Next.js] SSR이란 무엇인가? - Next.js의 서버 사이드 렌더링 이해하기 (1) | 2025.03.12 |
[Next.js] styled-components(CSS in JS)를 Next.js에서 사용한다고??! 🚨 (1) | 2025.03.11 |
[Next.js] Next.js + TypeScript 프로젝트 생성하기 ⚒️ (2) | 2025.03.09 |