Web サイトを作ると、ヘッダーやフッター、ナビゲーションメニューのように「どのページでも同じように表示したい部分」が必ず出てきます。これをページごとに書いていては、修正のたびにすべてのファイルを直すことになり大変です。Next.js の App Router では、こうした共通部分を layout.tsx にまとめておくことで、全ページで自動的に共有できます。この記事では、必須となるルートレイアウトと children の役割、フォルダごとにレイアウトを入れ子にする方法、ページを移動しても状態が保たれる特徴、そして page.tsx との違いまでを、初心者向けに解説します。
目次
layout.tsx とは何か
layout.tsx は、App Router で「複数のページに共通する枠組み」を定義するための特別なファイルです。app フォルダの中に置くと、その配下のすべてのページを包む形で使われます。page.tsx が「そのページ固有の中身」を担当するのに対し、layout.tsx は「その中身を囲む共通の外側」を担当します。両者の役割を整理しておきましょう。
| ファイル | 役割 |
|---|---|
layout.tsx | ヘッダー・フッターなど、複数ページで共通の外枠 |
page.tsx | そのURLでだけ表示される、ページ固有の中身 |
ルートレイアウトは必須
App Router では、app/layout.tsx(ルートレイアウト)が必ず1つ必要です。これはアプリ全体を包む一番外側のレイアウトで、<html> タグと <body> タグを含める決まりになっています。ここに書いた内容は、すべてのページで共有されます。
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ja">
<body>
<header>サイト共通ヘッダー</header>
{/* ここに各ページの中身が入る */}
<main>{children}</main>
<footer>© 2026 My Site</footer>
</body>
</html>
);
}
ポイントは children(子要素)という props です。{children} と書いた場所に、表示中のページの中身(page.tsx の内容)が差し込まれます。上の例なら、ヘッダーとフッターはどのページでも共通で表示され、その間の <main> の部分だけがページごとに入れ替わります。ヘッダーやフッターを直したいときは、この app/layout.tsx を1か所直すだけで全ページに反映されます。
children で各ページが差し込まれる仕組み
children の型に使っている React.ReactNode は、「React が表示できるもの全般」を表す型です。文字列や数値、JSX の要素など、画面に描けるものはすべてこれに当てはまります。レイアウトは中身が具体的に何であるかを知る必要がなく、「渡されたものをここに表示する」とだけ決めておけばよいので、この型を使います。
たとえば app/page.tsx(トップページ)と app/about/page.tsx(Aboutページ)があるとき、/ を開けばトップの中身が、/about を開けば About の中身が、それぞれ layout.tsx の {children} の位置に入ります。ヘッダーとフッターは共通のまま、中身だけが切り替わるわけです。
// このページの中身が layout.tsx の {children} に入る
export default function AboutPage() {
return <h1>このサイトについて</h1>;
}
フォルダごとにレイアウトを入れ子にする
layout.tsx はルートだけでなく、任意のフォルダに置けます。あるフォルダに layout.tsx を置くと、その配下のページだけに追加の共通レイアウトが適用され、ルートレイアウトの中に入れ子(ネスト)になります。たとえば管理画面(dashboard)にだけサイドバーを付けたい、といった場合に便利です。
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div style={{ display: 'flex' }}>
<aside>管理メニュー</aside>
{/* dashboard 配下のページだけがここに入る */}
<section>{children}</section>
</div>
);
}
この app/dashboard/layout.tsx は、/dashboard 以下のページにだけサイドバーを追加します。表示の構造としては、外側からルートレイアウト(ヘッダー・フッター)、その内側に dashboard のレイアウト(サイドバー)、さらにその内側に各ページの中身、という三重の入れ子になります。共通部分をどの範囲で共有したいかに応じて、レイアウトを置くフォルダを選べるのが App Router の大きな利点です。
ページを移動しても状態が保たれる
layout.tsx のもう一つの重要な特徴が、ページを移動してもレイアウトは再描画されず、状態が保たれるという点です。たとえばサイドバーのメニューを開いた状態でページを移動しても、そのサイドバーは作り直されないため、開いた状態のまま維持されます。共通のナビゲーションが遷移のたびにチラついたりリセットされたりしないので、快適な操作感につながります。
変わるのは {children} の部分、つまり移動先のページの中身だけです。この「変わらない外枠」と「切り替わる中身」という分担こそが、レイアウトを共通化する最大のメリットといえます。
うまく表示されないとき
ルートレイアウトに html・body がない
ルートレイアウト(app/layout.tsx)には <html> と <body> を必ず含める必要があります。これらを書き忘れるとエラーになります。ページ全体の土台となるタグなので、ルートレイアウトだけの決まりごととして覚えておきましょう。一方、フォルダ配下のネストしたレイアウトには <html>・<body> を書きません。
children を表示するのを忘れている
レイアウトの中に {children} を書き忘れると、ヘッダーやフッターは表示されるのに肝心のページの中身が出てこない、という状態になります。共通部分を書いたら、必ず {children} を置く場所を用意しているか確認しましょう。ページの中身がどこに入るかを決めるのは、この {children} です。
まとめ
Next.js App Router の layout.tsx は、ヘッダーやフッターのような共通部分を1か所にまとめ、全ページで共有するための仕組みです。app/layout.tsx のルートレイアウトは必須で、<html>・<body> を含み、{children} の位置に各ページの中身が差し込まれます。フォルダごとに layout.tsx を置けば、特定の範囲だけに追加のレイアウトを入れ子で適用でき、ページ移動時もレイアウトは再描画されず状態が保たれます。「変わらない外枠」と「切り替わる中身」を分けて考えることで、修正しやすく操作感のよいサイトが作れます。