TS-Tech
Next.js

App Router のファイルベースルーティング

6
  • ルーティング

App Router のファイルベースルーティング — Next.js Tips

/ は動いているが /about を足したい、/blog/記事名 のように URL を増やしたい——そんなとき、触るのはほぼ src/app/ 以下のフォルダと page.tsx だけです。App Router ではフォルダ名が URL になり、決まった名前のファイル(layout.tsx など)が役割を持ちます。

「Docker で Next.js の環境を構築する」で my-next-app を用意し、docker compose up -d のあと docker compose psUp (healthy) になっている状態を前提にします。Next.js 16 系を想定しています。

参考: Next.js — Project structure · Next.js — Defining Routes


目次

  1. App Router とは
  2. 事前準備
  3. 最小ルートの作り方
  4. ネストしたルート
  5. 動的セグメント
  6. 手順と確認(Docker)
  7. トラブルシュート
  8. 関連リンク

App Router とは

Next.js 13 以降、ルーティングの中心は app/ ディレクトリ(App Router)です。従来の pages/(Pages Router)と違い、フォルダ構造が URL に直結し、レイアウトやローディング UI をファイル名の規約で宣言できます。

観点 Pages Router App Router
ルート定義 pages/about.tsx/about app/about/page.tsx/about
レイアウト _app.tsx で全体を包む 各フォルダに layout.tsx
デフォルト クライアント寄り Server Components がデフォルト

本記事は App Router 前提です。新規プロジェクトでは App Router を選びましょう。

URL とフォルダの対応(概念図)

flowchart LR subgraph app["src/app/"] page["page.tsx → /"] about["about/page.tsx → /about"] blog["blog/[slug]/page.tsx → /blog/:slug"] end Browser["ブラウザの URL"] --> page Browser --> about Browser --> blog

事前準備

項目 要件
プロジェクト 「Docker で Next.js の環境を構築する」で作成した my-next-app
開発サーバー docker compose up -d 後、docker compose psUp (healthy)(ログに Ready も確認)
エディタ 任意(src/app/ 配下を編集)

ホストに Node.js は不要です。ファイルを保存すると、コンテナ内の next dev がホットリロードします。パスは src/app/ 前提です。


最小ルートの作り方

トップページは src/app/page.tsx です。このファイルが / に対応します。

// src/app/page.tsxexport default function HomePage() {  return (    <main>      <h1>トップページ</h1>      <p>App Router の最小ルートです。</p>    </main>  );}

ルートを公開するには、そのフォルダに page.tsx(または page.js)が必須です。layout.tsx だけでは URL は生成されません。

/about を足すには src/app/about/page.tsx を作ります。

// src/app/about/page.tsxexport default function AboutPage() {  return (    <main>      <h1>About</h1>      <p>会社概要ページです。</p>    </main>  );}

保存後、http://localhost:3000/about を開くと表示されます(Docker を再起動する必要は通常ありません)。

特殊ファイル(おさらい)

loading.tsxerror.tsxroute.ts など、決まった名前のファイルも App Router にはあります。一覧は「プロジェクト構成を理解する」で整理済みです。本記事で主に使うのは page.tsx(画面)と layout.tsx(共通枠)です。page.tsxroute.ts は同じフォルダに置けません。UI と API は別フォルダに分けてください。


ネストしたルート

layout.tsx は子ルート全体を包みます。共通ヘッダーを root layout に置く例です。

// src/app/layout.tsximport type { Metadata } from "next";export const metadata: Metadata = {  title: "My App",};export default function RootLayout({  children,}: {  children: React.ReactNode;}) {  return (    <html lang="ja">      <body>        <header>          <nav>            <a href="/">Home</a> | <a href="/about">About</a>          </nav>        </header>        {children}      </body>    </html>  );}

src/app/blog/layout.tsx を追加すると、/blog 以下だけ別レイアウトにできます。

// src/app/blog/layout.tsxexport default function BlogLayout({  children,}: {  children: React.ReactNode;}) {  return (    <section>      <h2>ブログ</h2>      {children}    </section>  );}

レイアウトはネストされます。/blog/hello を開くと RootLayoutBlogLayoutpage の順で描画されます。


動的セグメント

URL の一部をパラメータにするには、フォルダ名を [param] にします。

src/app/blog/[slug]/page.tsx → /blog/my-first-post
// src/app/blog/[slug]/page.tsxtype Props = {  params: Promise<{ slug: string }>;};export default async function BlogPostPage({ params }: Props) {  const { slug } = await params;  return (    <main>      <h1>記事: {slug}</h1>    </main>  );}

Next.js 15 / 16 系では params が Promise です。await params してから slug を取り出します。

複数セグメントは src/app/shop/[category]/[id]/page.tsx のようにフォルダを重ねます。キャッチオール([...slug])やオプショナル([[...slug]])はここでは扱いません。


手順と確認(Docker)

my-next-app のプロジェクトルートで:

docker compose up -ddocker compose ps

期待する結果:

  • サービス webSTATUSUp (healthy)(ポート 0.0.0.0:3000->3000/tcp など)
  • まだ starting のときは数秒待ってから docker compose ps を再実行するか、docker compose logs webReady を確認

healthy になるまで src/app/ の編集に進まないでください。止めている場合は上記で起動してください。

1. ディレクトリをそろえる

src/app/├── layout.tsx          # 共通 header(下記コード)├── page.tsx            # /├── about/│   └── page.tsx        # /about└── blog/    ├── layout.tsx      # /blog 以下の見出し    └── [slug]/        └── page.tsx    # /blog/:slug

上記セクションのコードを layout.tsxpage.tsxabout/page.tsxblog/layout.tsxblog/[slug]/page.tsx に反映します。

2. 保存してブラウザで確認

URL 期待される表示
http://localhost:3000/ トップページ
http://localhost:3000/about About。上部に Home | About の header
http://localhost:3000/blog/demo 「ブログ」見出しの下に 記事: demo
存在しないパス デフォルトの 404(のちに not-found.tsx を追加可能)

docker compose のログに GET / 200Compiling /about などが出ていれば、配置はおおむね正しいです。画面が変わらないときはブラウザをハードリロードしてください。

3. 止めるとき

# 実行中ターミナルで Ctrl+C のあとdocker compose down

トラブルシュート

症状 よくある原因 対処
404 になる page.tsx の名前ミス・配置ミス フォルダ名 = URL セグメントか確認
レイアウトが二重 layout.tsx を深くネストしすぎ 共通化の範囲を見直す
params.slug が undefined params を await していない const { slug } = await params
API と page が競合 同フォルダに page.tsxroute.ts 別フォルダに分離
保存しても反映されない ブラウザキャッシュ・監視の遅延 ハードリロード。改善しなければ「Docker で Next.js の環境を構築する」の WATCHPACK_POLLING を確認
変更が一切拾われない Compose が止まっている docker compose up -dpsUp (healthy) を確認
STATUS が healthy にならない 起動直後・ビルド失敗 docker compose logs web を確認。Ready まで待つ

関連リンク

シェア