App Router Layout 설정하기

작성일: 2025. 10. 09최종 수정: 2025. 10. 11. 01시 38분

Layout이란

Layout은 여러 페이지에서 공유되는 UI를 말한다. Next.js App Router에서 Layout은 다음과 같은 특징을 가진다.

  • 페이지 전환 시 상태를 유지한다
  • 재렌더링되지 않는다
  • 인터랙션을 유지한다

기본 사용법

특정 폴더 안에 layout.tsx 파일을 만들면 해당 폴더와 하위 폴더의 모든 페이지가 이 Layout을 공유한다.

typescript
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <section>
      <nav>네비게이션 바</nav>
      <main>{children}</main>
    </section>
  )
}

위 코드에서 children prop으로 해당 Layout 안에 렌더링될 페이지나 하위 Layout을 받는다. Layout 컴포넌트는 반드시 children을 받아서 렌더링해야 한다.

Root Layout

app 디렉토리의 최상위에는 반드시 Root Layout이 있어야 한다. 이 Layout은 애플리케이션 전체에 적용되며, 다른 Layout과 달리 특별한 요구사항이 있다.

typescript
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="ko">
      <body>{children}</body>
    </html>
  )
}

Root Layout은 <html><body> 태그를 반드시 포함해야 한다. 이는 서버 사이드 렌더링 시 완전한 HTML 문서를 생성하기 위함이다.

Layout 중첩

폴더 구조에 따라 Layout은 자동으로 중첩된다.

plain
app/
├── layout.tsx          # Root Layout
└── dashboard/
    ├── layout.tsx      # Dashboard Layout
    └── settings/
        ├── layout.tsx  # Settings Layout
        └── page.tsx    # Settings Page

위와 같은 구조에서 /dashboard/settings 경로에 접근하면 다음 순서로 중첩된다.

  1. Root Layout이 Dashboard Layout을 감싼다
  2. Dashboard Layout이 Settings Layout을 감싼다
  3. Settings Layout이 Settings Page를 감싼다

각 Layout은 자신의 children으로 다음 단계의 Layout 또는 Page를 받는다.

Layout의 동작 방식

Layout은 페이지 전환 시 재렌더링되지 않는다. 예를 들어 /dashboard/analytics에서 /dashboard/settings로 이동할 때, 두 페이지가 같은 Dashboard Layout을 공유한다면 Dashboard Layout은 그대로 유지되고 내부의 페이지 컴포넌트만 교체된다.

이로 인해 다음과 같은 이점이 있다.

  • Layout 내부의 상태가 유지된다
  • 불필요한 재렌더링을 방지해 성능이 향상된다
  • Layout 내부의 인터랙티브한 요소가 초기화되지 않는다

Route Group으로 Layout 구성하기

Route Group은 폴더 이름을 괄호 (folderName)로 감싸서 만든다. 이렇게 만든 폴더는 URL 경로에 포함되지 않고, 단순히 라우트를 구조화하는 용도로만 사용된다.

Route Group의 활용

Route Group을 사용하면 다음과 같은 작업을 할 수 있다.

  • 팀, 기능, 관심사별로 라우트를 논리적으로 그룹화한다
  • 동일한 라우트 세그먼트 레벨에서 여러 개의 Root Layout을 정의한다
  • 특정 라우트에만 선택적으로 Layout을 적용한다

사용 예시

plain
app/
├── (marketing)/
│   ├── layout.tsx      # 마케팅 전용 Layout
│   ├── about/
│   │   └── page.tsx    # URL: /about
│   └── blog/
│       └── page.tsx    # URL: /blog
└── (shop)/
    ├── layout.tsx      # 쇼핑 전용 Layout
    ├── products/
    │   └── page.tsx    # URL: /products
    └── cart/
        └── page.tsx    # URL: /cart

위 구조에서 (marketing)(shop)은 URL에 포함되지 않는다. /about 페이지는 마케팅 Layout을 사용하고, /products 페이지는 쇼핑 Layout을 사용한다.

여러 Root Layout 만들기

Route Group을 사용하면 하나의 앱 안에서 완전히 다른 Root Layout을 여러 개 만들 수 있다.

plain
app/
├── (site)/
│   ├── layout.tsx      # 일반 사이트용 Root Layout
│   └── page.tsx        # URL: /
└── (admin)/
    ├── layout.tsx      # 관리자용 Root Layout
    └── page.tsx        # URL: /admin (route group 내부에서는 /page로 처리)

다만 서로 다른 Root Layout 사이를 이동할 때는 전체 페이지가 다시 로드된다. 같은 Root Layout 내에서 이동할 때처럼 부분 렌더링이 일어나지 않는다.

주의사항

공식 문서에서 언급하는 주의사항이다.

  • 서로 다른 Route Group에서 같은 URL 경로가 생기지 않도록 해야 한다. 예를 들어 (shop)/products/page.tsx(marketing)/products/page.tsx는 둘 다 /products URL을 만들기 때문에 충돌이 발생한다.
  • 여러 Root Layout을 사용할 때, 홈 페이지 /는 반드시 하나의 Route Group 안에 정의되어야 한다.

참고 자료