4.2
Layouts
웹사이트에서 레이아웃(Layout)은 여러 웹페이지 간에 반복적으로 나타나는 화면 구성를 의미합니다. 이러한 레이아웃은 사용자가 페이지를 이동하더라도 사라지거나 다시 렌더링 되지 않고 계속해서 화면에 존재하게 됩니다. 일반적인 웹사이트는 가장 상단에 나오는 Header와 하단에 나오는 Footer가 페이지를 이동하더라도 사라지지 않고 고정적으로 나오는데, 이것은 Header와 Footer가 모두 레이아웃에 속해 있기 때문입니다. 아래 예시 화면에 나타난 두 개의 페이지는 서로 다른 페이지이지만, Header는 레이아웃에 속해있기 때문에 동일하게 나오는 것을 볼 수 있습니다.

Next.js의 App Router에서 이러한 레이아웃을 구성하기 위해서는 아래 그림과 같이 layout.js 라는 정해진 파일명을 사용하면 됩니다. 참고로 페이지 컴포넌트와 동일하게 JSX를 사용할 경우 파일 명은 layout.jsx, TypeScript의 경우 layout.tsx가 됩니다.
아래 그림은 레이아웃을 적용하는 예시를 나타낸 것입니다. 이 경우에 /posts로 접속하거나 /posts/1, /posts/2 등으로 접속했을 때 모두 /app/posts/layout.js 파일에 있는 레이아웃이 적용됩니다. 그래서 레이아웃을 페이지의 상위 컴포넌트(HOC, Higher Order Component) 라고 생각하면 이해하기 쉽습니다.
Next.js 레이아웃의 한 가지 중요한 특징은 경로 이동 시에도 상태(state)가 보존된다는 점입니다. 즉, 경로가 변경 되더라도 사용자와 상호작용 가능한 상태를 유지하며, 다시 렌더링 되지 않습니다. 레이아웃의 이러한 특징을 잘 이해하고 사용하는 것이 중요합니다. 그렇지 않으면 페이지를 이동했는데 레이아웃에 재렌더링이 발생하지 않고 그대로인 것에 대해서 의문을 가지고 디버깅하는데 시간을 허비할 수 있기 때문입니다.
Next.js 애플리케이션의 최상위 레이아웃을 Root Layout이라고 부릅니다. Root Layout은 이름이 가진 의미 그대로 애플리케이션 전체에 적용되는 레이아웃입니다. 그래서 App Router를 사용하는 모든 Next.js 애플리케이션에는 Root Layout이 필수적으로 존재해야 합니다. Root Layout은 아래 그림과 같이 App Router의 최상위 경로(app 폴더의 최상위 레벨)에 위치하게 되며, 이를 통해 애플리케이션 전체에 적용할 공통적인 레이아웃을 정의하게 됩니다.
App Router의 Root Layout은 html 태그와 body 태그를 필수적으로 포함해야 합니다. 앞서 배웠던 Pages Router에서는 Document(_document.tsx 파일)를 사용해서 index.html 파일을 구성하게 되는데, App Router에서는 Root Layout이 그 역할을 한다고 이해하면 됩니다.
아래 코드는 타입스크립트로 작성한 Root Layout 예시 코드입니다. 레이아웃은 페이지를 포함하는 컴포넌트이기 때문에, 아래 코드처럼 리액트 컴포넌트의 children 속성을 거의 필수적으로 사용합니다. 여기서 children은 페이지 또는 하위에 중첩된 레이아웃이 될 수 있습니다.
// app/layout.tsx
interface RootLayoutProps {
children: React.ReactNode;
}
function RootLayout(props: RootLayoutProps) {
const { children } = props;
return (
<html lang="en">
<body>
{/* 실제 레이아웃 UI */}
<main>
<header></header>
{children}
<footer></footer>
</main>
</body>
</html>
);
}
export default RootLayout;
웹사이트를 개발하다 보면 Root Layout 내에 각 경로 별로 또 다른 레이아웃을 중첩해서 적용하고 싶은 경우가 있습니다. 그럴 경우에는 아래 그림과 같이 해당 경로의 폴더 내에 별도의 layout.js 파일을 작성하면 됩니다.
아래 코드는 posts 폴더 내에 작성한 레이아웃 예시 코드입니다.
// app/posts/layout.tsx
interface PostLayoutProps {
children: React.ReactNode;
}
function PostLayout(props: PostLayoutProps) {
const { children } = props;
return <section>{children}</section>;
}
export default PostLayout;
위와 같이 중첩 레이아웃을 작성하면, 아래 그림과 같이 Root Layout과 Post Layout이 중첩되어 나타나게 됩니다. 물론 Post Layout은 /posts에 속한 경로로 접속했을 때만 중첩되어 나타나게 되며, / 경로로 접속했을 때는 Root Layout만 나타나게 됩니다. 여기서 기억할 점은 Root Layout을 포함해서 해당 페이지가 있는 폴더에 이르기까지 존재하는 모든 레이아웃이 다 중첩된다는 점입니다. 그래서 하나의 페이지에 하나의 레이아웃만 적용되는 것이 아니라, 하나의 페이지에 여러 개의 레이아웃이 중첩될 수 있습니다.
만약 특정 페이지에서 레이아웃을 중첩시키지 않고, 독립적인 레이아웃을 적용하고 싶다면 이전 장에서 나왔던 Route Groups를 사용해서 여러 개의 Root Layout을 만들면 됩니다. app 폴더의 최상위에 위치한 Root Layout 파일(layout.js 파일)을 제거하고, 아래 그림과 같이 각 Route Group에 layout.js 파일을 작성하는 것이죠. 이 때 각 Root Layout에 <html> 태그와 <body> 태그가 추가되어야 한다는 점을 꼭 기억하기 바랍니다.
마지막 업데이트: 2025년 10월 24일 02시 07분
이 문서의 저작권은 이인제(소플)에 있습니다. 무단 전재와 무단 복제를 금합니다.
On this page