현록

Next.js App Router에서 레이아웃 사용하기

Next.js의 App Router에서는 레이아웃이 파일 시스템 라우팅의 일부가 되었다.
예전처럼 모든 페이지에서 직접 <DefaultLayout>을 감싸는 방식도 가능하지만, 새 프로젝트라면 app/layout.tsx를 먼저 이해하는 편이 좋다.

기본 구조

App Router에서는 app 디렉토리 아래에 라우트 세그먼트를 만들고, 각 세그먼트에 특별한 파일을 배치한다.

  • page.tsx: 해당 경로에서 보여줄 페이지
  • layout.tsx: 해당 경로와 하위 경로를 감싸는 레이아웃
  • loading.tsx: 로딩 UI
  • error.tsx: 에러 UI
  • not-found.tsx: 404 UI

가장 기본이 되는 파일은 루트 레이아웃이다.

// app/layout.tsx
import type { Metadata } from 'next'
import './globals.css'

export const metadata: Metadata = {
  title: 'My App',
  description: 'Next.js App Router example',
}

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

루트 레이아웃은 반드시 htmlbody 태그를 포함해야 한다.
여기에 전역 CSS, 공통 폰트, 전역 provider, 기본 메타데이터처럼 앱 전체에 필요한 설정을 모아둘 수 있다.

페이지 만들기

page.tsx는 특정 URL에서 실제로 렌더링되는 UI다.

// app/page.tsx
export default function HomePage() {
  return <main>홈 화면입니다.</main>
}

app/page.tsx/ 경로가 되고, app/posts/page.tsx/posts 경로가 된다.

// app/posts/page.tsx
export default function PostsPage() {
  return <main>포스트 목록입니다.</main>
}

중첩 레이아웃 만들기

특정 경로 아래에서만 다른 공통 UI가 필요하다면 해당 세그먼트에 layout.tsx를 추가한다.

// app/posts/layout.tsx
export default function PostsLayout({ children }: { children: React.ReactNode }) {
  return (
    <section>
      <aside>포스트 카테고리</aside>
      <div>{children}</div>
    </section>
  )
}

이 레이아웃은 /posts/posts/[slug] 같은 하위 경로에 적용된다.
루트 레이아웃이 앱 전체를 감싸고, posts 레이아웃이 그 안에서 포스트 영역만 다시 감싸는 구조가 된다.

Pages Router 방식과 다른 점

예전 Pages Router에서는 페이지 컴포넌트 안에서 직접 레이아웃 컴포넌트를 import해 감싸는 경우가 많았다.

import DefaultLayout from '@/components/layout/DefaultLayout'

export default function HomePage() {
  return (
    <DefaultLayout>
      <main>홈 화면입니다.</main>
    </DefaultLayout>
  )
}

App Router에서는 이 반복을 파일 구조로 옮길 수 있다.
공통 UI는 layout.tsx에 두고, 페이지는 해당 경로의 본문에 집중하는 식이다.

언제 layout에 넣고 언제 component로 둘까요?

여러 페이지에 항상 적용되는 구조라면 layout.tsx에 둔다.

  • 상단 내비게이션
  • 푸터
  • 공통 사이드바
  • 인증 provider
  • 테마 provider

반대로 특정 화면 내부에서만 쓰는 UI라면 일반 컴포넌트로 분리하는 편이 낫다.

  • 카드 목록
  • 검색 필터
  • 상세 페이지의 추천 영역
  • 특정 폼의 입력 그룹

라우팅 계층과 생명주기를 공유해야 하는 공통 구조는 layout, 재사용 가능한 화면 조각은 component로 나누면 이해하기 쉽다.

참고 자료

관련 포스트
Next.js App Router에서 검색 날짜와 사이트맵 관리하기 thumbnail
Next.js App Router에서 검색 날짜와 사이트맵 관리하기
Next.js App Router 블로그에서 사용자에게 보이는 날짜, Open Graph modifiedTime, JSON-LD dateModified, sitemap lastModified를 같은 기준으로 연결하는 방법을 정리합니다.
Next.js 16 Cache Components와 use cache 정리 thumbnail
Next.js 16 Cache Components와 use cache 정리
Next.js 16에서 도입된 Cache Components와 use cache directive를 기준으로 App Router 캐싱 모델의 변화, cacheLife, cacheTag, revalidateTag 사용 흐름을 정리합니다.
next image blurDataURL 직접 부여하기 thumbnail
next image blurDataURL 직접 부여하기
Next.js의 Image 컴포넌트에서 blur placeholder를 사용할 때 자동 생성되는 경우와 직접 blurDataURL을 만들어야 하는 경우를 정리합니다. 정적 import, public 경로, 원격 이미지, 빌드 시점 생성 전략을 함께 다룹니다.
Next.js에서 path alias 설정하기 (feat. @/components) thumbnail
Next.js에서 path alias 설정하기 (feat. @/components)
오늘은 Next.js에서 import 시 복잡한 relative path 대신 absolute path 사용을 위한 설정법을 알아봅시다. file path를 상대경로로 지정하다보면 유지보수면에서도 복잡하고, path를 지정할 때마다 경로가 헷갈려서 발생하는 오류는 덤입니다. 이럴 때 path에 대한 alias를 설정하면 코드는 확 깔끔해질 것입니다.  아래 예제를 통해서 따라해봅시다.
Next.js에서 레이아웃 사용하기 thumbnail
Next.js에서 레이아웃 사용하기
홈페이지를 구성할 때, 우리는 대체로 네비게이션과 푸터, 플로팅 버튼 등을 포함합니다. 개발단계에서 이들 컴포넌트를 페이지마다 일일이 import하는 것은 매우 비효율적인 일입니다. 만약 이들처럼 대부분의 페이지에서 보여줘야될 내용이 있다면, 레이아웃 컴포넌트를 통해 손쉽게 유지보수할 수 있을 것입니다.