icon
4장 : 라우팅 심화

라우트 그룹 활용하기

App Router의 강력함은 단순히 URL 경로를 파일 시스템으로 매핑하는 것을 넘어, 개발자가 더 유연하고 체계적으로 라우트 구조를 관리할 수 있도록 지원하는 데 있습니다. 그 중심에 있는 기능 중 하나가 바로 라우트 그룹(Route Groups) 입니다.

라우트 그룹은 특정 폴더들을 URL 경로에 영향을 주지 않으면서 논리적으로 묶거나, 특정 그룹에만 고유한 레이아웃을 적용하고 싶을 때 사용됩니다. 이는 복잡한 애플리케이션에서 라우트 구조를 깔끔하게 유지하고, 다양한 레이아웃 요구사항을 효율적으로 처리할 수 있게 해줍니다.


라우트 그룹이란 무엇인가요?

라우트 그룹은 폴더 이름을 괄호(()) 로 감싸서 정의합니다. 예를 들어 (marketing), (auth)와 같이 생성할 수 있습니다.

라우트 그룹의 주요 특징

  • URL 경로에 영향 없음: 라우트 그룹 폴더는 실제 URL 경로에는 나타나지 않습니다. 즉, app/(marketing)/about/page.tsx/about 경로에 매핑됩니다.
  • 논리적 그룹화: 개발자가 관련된 라우트들을 한데 모아 관리하기 위한 목적으로 사용됩니다. 예를 들어, (marketing), (dashboard), (auth) 등 기능별로 그룹화할 수 있습니다.
  • 독립적인 레이아웃 적용: 가장 중요한 활용 사례 중 하나는 특정 라우트 그룹에만 고유한 레이아웃을 적용하는 것입니다. 예를 들어, 웹사이트의 마케팅 페이지들은 특정 레이아웃을 사용하고, 대시보드 페이지들은 또 다른 레이아웃을 사용할 때 유용합니다.
  • layout.tsx와 함께 사용: 라우트 그룹 안에 layout.tsx 파일을 정의하면, 해당 그룹 내의 모든 페이지와 중첩 라우트에 그 레이아웃이 적용됩니다.

라우트 그룹 활용 실습

이전 절에서 대시보드 레이아웃을 만들어 보았습니다. 이제 마케팅 관련 페이지들(예: 홈, 소개, 문의)에는 또 다른, 독립적인 레이아웃을 적용하고 싶다고 가정해 봅시다.

목표 구조

  • 마케팅 섹션: 홈 (/), 소개 (/about), 문의 (/contact)
    • 이 페이지들은 RootLayout을 공유하지만, 만약 (marketing) 그룹 내부에 별도의 레이아웃을 추가한다면 그 레이아웃이 중첩될 수 있습니다.
  • 대시보드 섹션: 대시보드 홈 (/dashboard), 개요 (/dashboard/overview) 등
    • 이 페이지들은 (dashboard) 그룹 내의 DashboardLayout을 공유하며, 이 또한 RootLayout 내부에 중첩됩니다.

실습 단계

  1. src/app/(marketing) 라우트 그룹 생성: src/app 디렉터리 안에 (marketing)이라는 이름의 새 폴더를 생성합니다. 그리고 기존에 src/app/page.tsxsrc/app/about/page.tsx가 있다면 이 파일들을 (marketing) 폴더 안으로 이동시킵니다. 또한, src/app/contact 페이지를 새로 만들어 (marketing) 폴더 안에 추가해 보세요.

    my-next-app/
    └── src/
        └── app/
            ├── (marketing)/      <- 여기에 (marketing) 폴더 생성
            │   ├── page.tsx      <- 기존 src/app/page.tsx 이동
            │   ├── about/        <- 기존 src/app/about 폴더 이동
            │   │   └── page.tsx
            │   └── contact/      <- 새로 생성
            │       └── page.tsx
            ├── dashboard/
            │   ├── layout.tsx
            │   └── ...
            └── layout.tsx        <- 최상위 루트 레이아웃은 그대로
    • src/app/(marketing)/contact/page.tsx 내용
      src/app/(marketing)/contact/page.tsx
      // src/app/(marketing)/contact/page.tsx
      export default function ContactPage() {
        return (
          <div>
            <h3>문의하기</h3>
            <p>궁금한 점이 있다면 언제든지 문의해주세요.</p>
          </div>
        );
      }
  2. src/app/(dashboard) 라우트 그룹 생성: 이제 src/app/dashboard 폴더를 src/app/(dashboard)로 이름을 변경하여 라우트 그룹으로 만듭니다. 이 폴더 안에 있는 layout.tsx와 다른 페이지 파일들은 그대로 유지합니다.

    my-next-app/
    └── src/
        └── app/
            ├── (marketing)/
            │   └── ...
            ├── (dashboard)/      <- src/app/dashboard 폴더를 (dashboard)로 이름 변경
            │   ├── layout.tsx
            │   └── ...
            └── layout.tsx
  3. 루트 레이아웃의 <nav> 링크 업데이트: src/app/layout.tsx 파일의 내비게이션 링크들을 업데이트하여 새로 만든 contact 페이지로 가는 링크도 추가합니다.

    // src/app/layout.tsx (일부)
    // ...
            <header style={{ backgroundColor: '#f0f0f0', padding: '10px', borderBottom: '1px solid #ddd' }}>
              <nav>
                <Link href="/"><a></a></Link> | {' '}
                <Link href="/about"><a>소개</a></Link> | {' '}
                <Link href="/contact"><a>문의</a></Link> | {' '} {/* 새 링크 추가 */}
                <Link href="/dashboard"><a>대시보드</a></Link>
              </nav>
              <h1>나 혼자 Next.js</h1>
            </header>
    // ...

실습 확인: 개발 서버(npm run dev)를 실행한 후, 다음 URL들을 방문하며 URL 경로가 어떻게 유지되는지 확인해 보세요.

  • http://localhost:3000/ (여전히 홈 페이지)
  • http://localhost:3000/about (여전히 소개 페이지)
  • http://localhost:3000/contact (새로 만든 문의 페이지)
  • http://localhost:3000/dashboard (여전히 대시보드 홈)

라우트 그룹으로 폴더를 묶었지만, URL 경로에는 아무런 변화가 없습니다. 이것이 라우트 그룹의 가장 기본적인 역할입니다.


라우트 그룹별 독립적인 레이아웃 적용

이제 라우트 그룹의 진정한 강점인, 그룹별 독립적인 레이아웃 적용을 해보겠습니다. 만약 마케팅 페이지들에는 특정 헤더나 푸터가 대시보드 페이지와 다르게 필요하다면, (marketing) 그룹 내부에 layout.tsx를 정의할 수 있습니다.

  1. src/app/(marketing)/layout.tsx 생성: src/app/(marketing) 폴더 안에 layout.tsx 파일을 생성하고 다음 내용을 작성합니다.

    src/app/(marketing)/layout.tsx
    // src/app/(marketing)/layout.tsx
    
    export default function MarketingLayout({
      children,
    }: {
      children: React.ReactNode;
    }) {
      return (
        <div style={{ border: '2px dashed #0070f3', padding: '20px', margin: '20px 0', borderRadius: '10px' }}>
          <h2 style={{ color: '#0070f3' }}>마케팅 섹션 (그룹 레이아웃)</h2>
          {children}
        </div>
      );
    }

    설명

    • MarketingLayout(marketing) 그룹 내의 모든 페이지(홈, 소개, 문의)에 적용됩니다.
    • 이 레이아웃은 RootLayoutchildren으로 렌더링되고, 이 레이아웃의 children으로 다시 해당 페이지의 page.tsx 콘텐츠가 렌더링되는 중첩 구조를 가집니다.

실습 확인: 개발 서버를 다시 확인하고 다음 URL들을 방문해 보세요.

  • http://localhost:3000/
  • http://localhost:3000/about
  • http://localhost:3000/contact

이 세 페이지에서는 이제 최상위 헤더/푸터(RootLayout) 안에, 파란색 점선 테두리를 가진 "마케팅 섹션" 영역(MarketingLayout)이 보이고 그 안에 페이지 콘텐츠가 나타날 것입니다. 반면, http://localhost:3000/dashboard로 접속하면 DashboardLayout이 여전히 적용되는 것을 볼 수 있습니다.

이처럼 라우트 그룹을 사용하면 URL 경로를 깔끔하게 유지하면서도, 필요에 따라 다양한 레이아웃을 유연하게 적용할 수 있습니다. 이는 특히 대규모 애플리케이션이나 여러 섹션이 독립적인 디자인을 가질 때 매우 유용합니다.


주의사항

동일한 URL 세그먼트를 가진 여러 라우트 그룹을 만들 수도 있습니다. 예를 들어, (auth)/login/page.tsx(admin)/login/page.tsx는 모두 /login 경로로 매핑됩니다. 이 경우 Next.js는 어떤 page.tsx를 렌더링해야 할지 모호해지므로 에러가 발생합니다.

따라서, 각 라우트 그룹의 최종 URL 경로는 고유해야 합니다. 라우트 그룹은 레이아웃이나 폴더 구조를 위한 논리적 그룹화에 사용하고, 실제 URL 충돌이 발생하지 않도록 주의해야 합니다.

라우트 그룹은 Next.js App Router의 구조화 및 유연성을 높이는 데 핵심적인 역할을 합니다. 이를 잘 활용하면 복잡한 애플리케이션도 효율적으로 관리하고 확장할 수 있습니다.