Next.js のレイアウトの全体像
React 単体だと、ページごとにヘッダーやフッターを書きがちです。
でも実際のサイトを想像すると、ほとんどのページで「共通の部分」があります。
画面の一番上にあるヘッダー。
左にあるナビゲーション。
一番下のフッター。
これを毎ページにベタ書きすると、修正が地獄になります。
Next.js の App Router では、この「共通部分」をまとめて管理するために layout.tsx という仕組みが用意されています。
ここに Next.js らしさ がかなり詰まっています。
layout.tsx の役割と仕組み
layout.tsx は「その階層の共通枠」
App Router では、page.tsx が「その URL の中身」、layout.tsx が「その URL 階層の共通レイアウト」を担当します。
例えば app 直下にある layout.tsx は、全ページ共通の枠になります。
つまり、どのページに行っても共通で表示されるヘッダーやフッターは、ここに書くのが基本です。
イメージとしては、
外側の大きな箱 → layout.tsx
その中に入るページごとの中身 → page.tsx
という二重構造です。
layout.tsx の中では、「子のコンテンツが入る場所」として children を受け取ります。
この children の位置に、その階層の page.tsx やさらに下のレイアウト・ページが差し込まれます。
共通ヘッダーを layout.tsx で作る
最小の layout.tsx の形
Next.js の App Router プロジェクトを作ると、最初から app/layout.tsx が用意されているはずです。
典型的な例は次のような形です(少し簡略化します)。
// app/layout.tsx
import type { ReactNode } from "react";
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="ja">
<body>{children}</body>
</html>
);
}
TSXここではまだ共通ヘッダーはありませんが、
「全ページ共通で html や body をラップしているレイアウト」が定義されています。
共通ヘッダーを追加してみる
ここに、サイト共通のヘッダーを追加してみます。
// app/layout.tsx
import type { ReactNode } from "react";
import Link from "next/link";
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="ja">
<body style={{ margin: 0, fontFamily: "sans-serif" }}>
<header
style={{
padding: "12px 24px",
backgroundColor: "#111827",
color: "white",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<div>Next.js × React 入門</div>
<nav style={{ display: "flex", gap: "16px" }}>
<Link href="/">ホーム</Link>
<Link href="/about">このサイトについて</Link>
</nav>
</header>
<main style={{ padding: "24px" }}>{children}</main>
</body>
</html>
);
}
TSXここで大事なのは children の位置です。
この children の部分に、各ページの page.tsx の内容が差し込まれます。
例えば、
/ にアクセス → app/page.tsx の中身が children に入る。/about にアクセス → app/about/page.tsx の中身が children に入る。
どちらのページにいても、ヘッダーは layout.tsx によって共通で表示され続けます。
レイアウトの仕組みをもう一段深く理解する
「入れ子のレイアウト」ができるのが強い
App Router のレイアウトは、「階層ごとに layout.tsx を置ける」のがポイントです。
例えば、こんな構成を考えます。
app/layout.tsxapp/page.tsxapp/dashboard/layout.tsxapp/dashboard/page.tsxapp/dashboard/settings/page.tsx
このときレイアウトは次のように入れ子になります。
全ページ共通の枠 → app/layout.tsx
ダッシュボード配下だけの共通枠 → app/dashboard/layout.tsx
その中に各ページの page.tsx が入る
例えば /dashboard の画面は、ざっくり言うと、
RootLayout で全体をラップ
その中に DashboardLayout が入り
さらにその中に /dashboard の page.tsx の中身が入る
という三重構造になります。
ダッシュボード専用レイアウトの例
ダッシュボード配下だけサイドバー付きレイアウトにするイメージです。
// app/dashboard/layout.tsx
import type { ReactNode } from "react";
import Link from "next/link";
export default function DashboardLayout({ children }: { children: ReactNode }) {
return (
<div style={{ display: "flex", minHeight: "calc(100vh - 60px)" }}>
<aside
style={{
width: "200px",
padding: "16px",
borderRight: "1px solid #e5e7eb",
}}
>
<h2>ダッシュボード</h2>
<nav>
<p><Link href="/dashboard">概要</Link></p>
<p><Link href="/dashboard/settings">設定</Link></p>
</nav>
</aside>
<section style={{ flex: 1, padding: "24px" }}>
{children}
</section>
</div>
);
}
TSXこれを置くだけで、/dashboard も /dashboard/settings も、
共通してこのサイドバー付きレイアウトの中で表示されます。
そしてその外側には、さらに app/layout.tsx のヘッダーなどが乗っている、という構造です。
ページ共通化の考え方
「何回も書いているところは layout に追い出す」
レイアウト分割の考え方は、とてもコンポーネント分割に似ています。
同じヘッダーを各ページの page.tsx に毎回書いているなら、それは layout.tsx に移動すべきです。
同じサイドバーをダッシュボード系ページで毎回書いているなら、それは app/dashboard/layout.tsx に切り出すべきです。
つまり、
ページ「ごと」に共通なものはコンポーネント化。
URL階層「全体」で共通なものはレイアウト化。
という感覚です。
layout と「普通のコンポーネント」の違い
どちらも JSX を返す点では同じですが、役割が違います。
普通のコンポーネント
好きな場所から呼び出す「部品」<Header /> や <Card /> など
layout.tsx
Next.js によって自動的に使われる「その階層の枠」children に、その階層のページや下のレイアウトが自動で入る
レイアウトは「この階層全体で使う共通枠」、コンポーネントは「好きなところで使う部品」として、頭の中で整理すると分かりやすいです。
実務での使い所
よくあるレイアウトのパターン
現場レベルでは、だいたいこんな使い方が多いです。
サイト全体共通レイアウト
グローバルヘッダー(ロゴ、グローバルメニュー)
フッター
全体の余白やフォント設定
特定セクションだけのレイアウト
管理画面やダッシュボード用のサイドバー付きレイアウト
マイページエリアだけの特殊なレイアウト
例えば、
一般ユーザー向けページ / や /about など
会員専用ページ /dashboard 配下
で、レイアウトを分けるのはかなりよくある構成です。
ユーザー側から見ると、「管理画面だけ雰囲気が違うけど、ヘッダーのロゴは共通」みたいなサイトって多いですよね。
それを、app/layout.tsx と app/dashboard/layout.tsx の組み合わせで表現できます。
デザイン変更に強くなる
実務だと、「ヘッダーのデザインを変えたい」「全ページの余白を広くしたい」などの要望は頻繁に出ます。
layout.tsx に共通部分を集約しておけば、
ロゴの位置を変える
共通メニューを追加する
全ページの main の幅を変える
といった修正を、基本的に 1カ所ずつ 直すだけで済みます。
ページごとに同じヘッダーをコピペしている状態だと、
すべてのページを手作業で修正するハメになります。
レイアウトをちゃんと設計しておくことが「後からのコスト」を大きく減らしてくれます。
まとめと一歩先の練習
ここまでのポイントを整理すると、こうなります。
Next.js App Router の layout.tsx は、その階層の「共通レイアウト(枠)」を定義するファイルで、children の位置に各ページの中身が差し込まれる。app/layout.tsx にヘッダーやフッターを置けば全ページ共通になり、特定のフォルダ内に layout.tsx を置けば、その配下の URL だけに適用されるレイアウトを作れる。
「よく使う部品」は通常のコンポーネントに、「URL 階層全体で共通の枠」は layout に追い出すと、コードが読みやすく、変更に強くなる。
実務では、全体レイアウトとダッシュボード用レイアウトなど、複数の layout を組み合わせて「ユーザー向けエリア」と「管理者向けエリア」を分ける、という使い方がよくある。
練習としては、次のような構成を自分で作ってみるのがおすすめです。
全体レイアウトにサイト共通ヘッダー。/dashboard 配下だけ、左にメニューがあるレイアウト。/dashboard と /dashboard/settings の2ページを作って行き来してみる。
これが動くようになると、「Next.js らしいレイアウト設計」がかなり体に染みてきます。
