---
title: "App Routerとは？Next.jsのファイル規約・動的ルーティング・Pages Routerとの違い"
url: "https://www.issoh.co.jp/tech/details/4026/"
published: 2024-11-01
updated: 2026-08-10
categories: ["Next.js"]
publisher: "株式会社一創"
---

# App Routerとは？Next.jsのファイル規約・動的ルーティング・Pages Routerとの違い

App Routerは、Next.jsの`app`ディレクトリでフォルダとファイルの配置そのものをURLの定義にするルーティング方式です。2023年5月のNext.js 13.4で安定版になり、それ以降に作られたプロジェクトの標準になりました。一方で、13系が公開された当時の記述が残る解説も多く、2026年8月時点の最新安定版16.3.0でそのまま書き換えると動かない、あるいはエラーも出ないまま値が壊れる箇所があります。この記事ではファイル規約と動的ルーティングの書き方を押さえたうえで、16.3.0を実際にインストールしてビルドし、13時代の記述がどこで通用しなくなったかまで確認します。

## まとめ

App Routerは`app`配下のフォルダ構造がそのままURLになる仕組みで、`page`がルートを作り、`layout`が共有UIを担います。Pages Routerの`getServerSideProps`や`next/head`に相当する仕組みは置き換えられており、移行時はこの3点（データ取得・メタデータ・`useRouter`の参照先）でまず詰まります。

実務でいちばん危険なのは、13時代のサンプルをそのまま持ち込んだときに**本番ビルド経路では何の異常も出ないまま値だけが壊れる**ケースです。Next.js 16では`params`がPromiseになったため、同期アクセスすると型注釈を書き換えただけでビルドが通り、描画結果が`undefined`になります。`next dev`なら明示的なエラーが出ますが、`next build`と`next start`の経路では出ません。手元の16.3.0で両方の挙動を確認しました。以下、ファイル規約から順に見ていきましょう。

## App Routerの定義と13.4での安定版化

App Routerは、`app`ディレクトリ内のフォルダをURLセグメントに対応させ、その中に置く決められた名前のファイルでUIを定義するルーティング方式です。ルートを設定ファイルに列挙する必要はありません。フォルダを掘って`page.tsx`を置けば、その時点でURLが増えます。

安定版になったのはNext.js 13.4です。公式ブログは2023年5月4日付で「Next.js 13.4 is a foundational release, marking stability for the App Router」と宣言し、React Server Components、ネストされたルートとレイアウト、ストリーミングとSuspenseを安定機能として挙げました。同じ記事のFAQでPages Routerの扱いも明言されており、「We are committed to supporting pages/ development, including bug fixes, improvements, and security patches, for multiple major versions moving forward」と継続サポートを約束しています。実際、最新安定版16.3.0のタグを見てもドキュメントには`02-pages`のディレクトリが残っており、Pages Routerは廃止されていません。

App Routerのコンポーネントは既定でサーバー側で実行されます。この仕組みそのものについては[React Server Components（RSC）とは？サーバー・クライアントの違いと使い分けを実装例で解説](/tech/details/4003/)で扱っているため、本記事はルーティングとファイル規約に絞ります。

## appディレクトリのファイル規約と実機ビルドで生成されたルート

### ルートを定義するpageと共有UIを担うlayout

覚えるべき最小単位は2つです。`page`を置いたフォルダだけが公開URLになり、`layout`はそのフォルダ以下で共有されるUIになります。フォルダを作っただけではURLは生えません。

```
app/
  layout.tsx              # ルートレイアウト（必須・html と body を含む）
  page.tsx                # URL: /
  not-found.tsx           # 404時のUI
  blog/
    layout.tsx            # /blog 配下で共有されるUI
    loading.tsx           # /blog 配下の読み込み中UI
    page.tsx              # URL: /blog
    [slug]/
      page.tsx            # URL: /blog/任意の値
  docs/
    [[...slug]]/
      page.tsx            # URL: /docs と /docs/任意の階層
  (marketing)/
    pricing/
      page.tsx            # URL: /pricing（括弧付きフォルダはURLに出ない）
  api/
    health/
      route.ts            # URL: /api/health（APIエンドポイント）
```

ルートレイアウトは必須で、`html`タグと`body`タグを自分で書きます。Pages Routerの`_app.js`と`_document.js`が担っていた役割が、この1ファイルに統合されたと考えると対応が取りやすくなります。

```
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ja">
      <body>{children}</body>
    </html>
  )
}
```

ネストされたフォルダに`layout`を追加すると、親のレイアウトが子のレイアウトを包む形で入れ子になります。ページ遷移してもレイアウトは再レンダリングされず状態を保持する、と公式ドキュメントは説明しています。

### loading・not-found・routeの役割分担

`page`と`layout`以外にも予約ファイル名があり、それぞれ配置した階層に対して効きます。よく使うものだけ挙げましょう。

| ファイル名     | 役割           | 効く範囲    |
| --------- | ------------ | ------- |
| page      | そのURLの本体     | 置いたフォルダ |
| layout    | 共有UI・状態を保持   | 配下すべて   |
| loading   | 読み込み中UI      | 配下すべて   |
| not-found | 404時のUI      | 配下すべて   |
| error     | 例外発生時のUI     | 配下すべて   |
| route     | APIエンドポイント   | 置いたフォルダ |
| default   | パラレルルートの既定表示 | 置いたスロット |

同じフォルダに`page`と`route`を同居させることはできません。手元で試すと`Conflicting route and page at /blog`でビルドが止まります。UIを返すのが`page`、レスポンスを返すのが`route`という住み分けです。なお`default`はNext.js 16で扱いが変わり、パラレルルートのスロットすべてに明示的な`default`が必要になりました。無いとビルドが失敗します。

### 実機ビルドで出力されたルート一覧

上のツリーどおりにファイルを置き、`next build`を実行した結果が次の出力です。Next.js 16.3.0とReact 19.2.0、Node.js v26.5.0の環境で取得しました。

```
▲ Next.js 16.3.0 (Turbopack)
✓ Running next.config took 38ms

  Creating an optimized production build ...
✓ Compiled successfully in 7.0s
（中略：TypeScript 検査・ページデータ収集・静的ページ生成・最適化）

Route (app)
┌ ○ /
├ ○ /_not-found
├ ƒ /api/health
├ ○ /blog
├ ƒ /blog/[slug]
├ ƒ /docs/[[...slug]]
└ ○ /pricing

○  (Static)   prerendered as static content
ƒ  (Dynamic)  server-rendered on demand
```

読み取れることが2つあります。1つはバナーの「(Turbopack)」で、オプションを何も付けていないのにTurbopackが使われている点。もう1つは`○`と`ƒ`の区別で、`/blog`は静的に事前生成され、`/blog/[slug]`はリクエストごとにサーバーで描画されるという判定がビルド時点で確定します。どのルートがどちらに倒れるかは、ここを見れば一目で分かります。静的生成と動的描画の選び分けそのものは[Next.jsのレンダリング方式｜SSG・ISR・SSR・CSRの違いとApp Routerでの選び方](/tech/details/3791/)で整理しました。

## 動的セグメントとルートグループの記法

### `[slug]`と`[[...slug]]`の使い分け

フォルダ名を角括弧で囲むと動的セグメントになります。`[slug]`は1階層ぶんを受け取り、`[...slug]`は残りのパスをすべて配列で受け取り、`[[...slug]]`はセグメントが1つも無い場合にもマッチします。上のビルド結果で`/docs/[[...slug]]`が1本のルートとして登録されているのは、`/docs`と`/docs/a/b`の両方を同じファイルで受けているためです。

```
// app/blog/[slug]/page.tsx
export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params
  return <h1>{slug}</h1>
}
```

ここで押さえるべきは`params`がPromiseである点です。非同期化そのものはNext.js 15の変更で、当時は同期アクセスも暫定的に許容されていました。16の移行ガイドは「Version 15 introduced Async Request APIs as a breaking change, with temporary synchronous compatibility. Starting with Next.js 16, synchronous access is fully removed」と述べており、16で猶予が終わっています。クライアントコンポーネントで受け取る場合はReactの`use`で解決します。動的セグメントは`page`だけでなく`layout`、`route`、`generateMetadata`にも同じ`params`として渡されます。

### 括弧付きフォルダがURLから消える挙動の実測

フォルダ名を丸括弧で囲むとルートグループになり、そのフォルダはURLに現れません。管理画面とマーケティングページでレイアウトを分けたいが、URLには階層を足したくないという場面で使います。チームや機能の単位でフォルダを整理する用途も公式に挙げられています。

この挙動は実際に確認しました。`app/(marketing)/pricing/page.tsx`を置いてビルドし、`next start`で起動したサーバーに問い合わせたところ、`/pricing`は200を返し、`/marketing/pricing`は404。ビルド出力のルート表にも`/pricing`としか出ません。

ただしURLへの影響が皆無というわけではないので、公式ドキュメントのCaveatsは押さえておいてください。別グループのルートが同じURLパスに解決する構成、たとえば`(marketing)/about/page.js`と`(shop)/about/page.js`はどちらも`/about`になるためエラーになります。またルートレイアウトを複数持つ場合、異なるルートレイアウト間の遷移はフルページリロードが発生します。

## App RouterとPages Routerの違いと選択基準

### データ取得・レンダリング・ルーティングの相違点

両者はディレクトリが違うだけでなく、データ取得の書き方とコンポーネントの実行場所が根本から異なります。主要な対応関係を並べます。

| 観点         | Pages Router       | App Router           |
| ---------- | ------------------ | -------------------- |
| ディレクトリ     | pages              | app                  |
| 既定のコンポーネント | クライアント             | サーバー                 |
| サーバー側取得    | getServerSideProps | コンポーネント内でawait       |
| ビルド時取得     | getStaticProps     | コンポーネント内でawait       |
| 静的パス列挙     | getStaticPaths     | generateStaticParams |
| メタデータ      | next/head          | Metadata API         |
| 共通レイアウト    | \_app・\_document   | layout（入れ子可）         |
| ルーターフック    | next/router        | next/navigation      |

「既定のコンポーネント」の行は補足が要ります。Pages Routerのページもサーバーで事前描画されてからクライアントでハイドレートされるため、サーバー描画が無いわけではありません。違うのは、App Routerの既定がクライアントへJavaScriptを送らないサーバーコンポーネントである点です。実務上の差がいちばん出るのはレイアウトのほうで、Pages Routerの`_app.js`は1つしか持てず入れ子にできませんでしたが、App Routerの`layout`はフォルダ階層ぶん重ねられます。管理画面のサイドバーを`/admin`配下だけで共有する、といった構成が設定なしで書けます。

### App Routerを選ばない方がよい条件

新規プロジェクトならApp Routerで問題ありません。`create-next-app`もApp Routerを既定のテンプレートにしています。判断が要るのは既存プロジェクトのほうで、次の2条件のいずれかに当てはまるなら、今は移行しないほうが合理的です。

1つ目は、`getServerSideProps`中心のページが多く残っている場合。Next.js 16へのバージョンアップだけでも、`params`の同期アクセス廃止、`middleware.ts`の改称、Turbopack既定化が同時に降ってきます。ここにルーティング方式の変更まで重ねると、不具合が出たときにどの変更が原因か切り分けられません。先に16へ上げてPages Routerのまま動かし、落ち着いてからルート単位で移すべきです。App RouterとPages Routerは同一プロジェクトで併用できます。

2つ目は、ページ数が少なく、ネストしたレイアウトもストリーミングも使わない静的なサイトです。`layout`・`loading`・`not-found`・`route`・`default`という予約ファイル名を覚える学習コストに見合いません。

なお、Edgeランタイムでのミドルウェア処理への依存は、よく移行のハードルとして挙げられますが、ルーター選択の判断材料にはなりません。`proxy`と`middleware`の規約はPages Router側のドキュメントにも同じように存在するため、どちらのルーターを使うかとは独立した論点です。16のアップグレード側の課題として別に片付けてください。

## Pages Routerからの移行でつまずく3点

### getServerSidePropsとgetStaticPropsの置き換え先

移行ガイドは「getServerSideProps, getStaticProps and getInitialProps have been replaced with a simpler API」と述べています。置き換え先は専用の関数ではなく、サーバーコンポーネント内での`await`です。取得したデータを`props`として返す必要はなく、コンポーネントの中で直接使います。`getStaticPaths`だけは後継の関数があり、`generateStaticParams`に名前が変わりました。

### next/headからMetadata APIへの移行

`next/head`は`app`ディレクトリでは使えません。移行ガイドは「In the app directory, next/head is replaced with the new built-in SEO support」と明記しています。代わりに`page`や`layout`から`metadata`オブジェクトをエクスポートするか、動的に組み立てるなら`generateMetadata`関数をエクスポートします。`generateMetadata`にも動的セグメントの`params`が渡るため、記事タイトルをURLのスラッグから引いてtitleに反映する、といった処理はここに書きましょう。

### useRouterの参照先変更とnext/compat/router

同じ`useRouter`という名前でも、`next/router`から取るものと`next/navigation`から取るものは別物です。公式ドキュメントは「The useRouter hook imported from next/router is not supported in the app directory but can continue to be used in the pages directory」としています。移行時は`next/navigation`へ切り替えたうえで、返り値の違いにも対応が必要です。新しい`useRouter`は`pathname`を返さず`usePathname`を使い、`query`も返さないため`useSearchParams`と`useParams`に分けて取得します。

両方のルーターで同じコンポーネントを共有している移行期間には、`next/compat/router`から`useRouter`を読む選択肢があります。ただし戻り値の型が`NextRouter | null`である点に注意してください。App Router側では`null`が返るため、`const { isReady, query } = useRouter()`のような分割代入をそのまま書くとエラーになります。App Routerに寄せ切ったら`next/navigation`へ更新しましょう。

## Next.js 13時代の解説が16で通用しない4点

ここが古い記事をそのまま読むと事故る部分です。Next.js 16は2025年10月21日公開で、App Router周辺の前提がいくつも変わりました。前提要件も上がっており、Node.js 20.9以上、TypeScript 5.1以上、ブラウザはChrome・Edge・Firefoxが111以上、Safariが16.4以上を要求します。以下、4点のうち最初の1点と後半2点は手元の16.3.0で挙動を確認したもの、キャッシュの節は公式ブログとドキュメントの記述にもとづくものです。バージョンごとの変更点全体は[Next.js 16とは？ReactベースのWeb開発フレームワーク最新版の概要や主要機能を詳しく紹介](/tech/details/9596/)にまとめています。

### paramsの同期アクセスがエラーなくundefinedになる罠

13時代のサンプルは`params.slug`を直接読んでいました。16では`params`がPromiseになっているため、この書き方では値を取り出せません。問題は、失敗の仕方が本番経路だけ静かなことです。

```
// 13時代の書き方をそのまま16に持ち込んだ場合
export default function Page({ params }: { params: { slug: string } }) {
  return <h1>slug={String(params.slug)}</h1>
}

// next build → next start して /blog/hello を取得した実測結果
//   ビルド終了コード: 0
//   HTTPステータス: 200
//   実HTML: <h1>slug=<!-- -->undefined</h1>  ← 表示は slug=undefined
```

ビルドは成功し、TypeScriptの検査も通り、本番サーバーのログにも警告は出ませんでした。それでも描画結果だけが`undefined`になります。`await params`に直した版では同じURLが`slug=hello`を返しました。

救いは開発サーバーです。同じコードを`next dev`で動かすと、次のエラーが該当行つきで表示されます。

```
Error: Route "/blog/[slug]" used `params.slug`. `params` is a Promise and must be
unwrapped with `await` or `React.use()` before accessing its properties.
Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
```

つまり開発中に一度でも該当ページを開いていれば気づけます。危ないのは、開発時に踏まなかった動的ルートがそのまま本番へ出ていくパターンです。動的セグメントを使っているページで値が空になる症状に出会ったら、まずここを疑ってください。

### キャッシュ既定の反転とCache Components

13系のApp Routerは、`fetch`の結果を既定でキャッシュする挙動が「暗黙的すぎる」と批判されてきました。この既定が覆されたのはNext.js 15で、移行ガイドに「fetch requests are no longer cached by default」と明記されています。ルートハンドラーの`GET`も同時に既定キャッシュをやめました。13時代の記事を読むときは、この一点だけでキャッシュ周りの記述が丸ごと古いと考えて構いません。

16はさらに一歩進め、キャッシュを明示的に選ぶ仕組みを入れました。公式ブログは「caching with Cache Components is entirely opt-in. All dynamic code in any page, layout, or API route is executed at request time by default」と述べており、キャッシュしたい箇所に`"use cache"`ディレクティブを書く形になっています。有効化は`next.config.ts`で`cacheComponents: true`を設定します。実験的フラグだった`experimental.ppr`は削除され、`experimental.dynamicIO`は`cacheComponents`へ改称されました。

あわせて`revalidateTag()`の引数も変わり、第2引数に`cacheLife`プロファイルを渡す形になりました。単一引数の呼び出しは非推奨で、公式ドキュメントは「It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version」としています。TypeScriptエラーを抑制しないと通らないため、古い記事の`revalidateTag('posts')`という記述はそのままでは書けません。

### middleware.tsからproxy.tsへの改称

`middleware.ts`は`proxy.ts`に置き換わりました。ファイル名を変え、エクスポートする関数名も`proxy`に変えるだけで、中のロジックはそのままで構いません。旧名のまま16でビルドすると次の警告が出ます。

```
⚠ The "middleware" file convention is deprecated. Please use "proxy" instead.

  To migrate automatically, run:
  npx @next/codemod@canary middleware-to-proxy .

  Learn more: https://nextjs.org/docs/messages/middleware-to-proxy
```

警告が出るだけでビルドは通り、ルート表には「ƒ Proxy (Middleware)」として登録されました。ただし`proxy`のランタイムは`nodejs`固定で、`edge`は選べません。移行ガイドも「If you want to continue using the edge runtime, keep using middleware」としており、Edge依存がある場合は旧名のまま残す判断になります。とはいえ`middleware.ts`は非推奨で、公式ブログは将来のバージョンで削除すると予告しています。Edge依存が無いなら、動いているうちにcodemodで移しておくのが安全です。

### Turbopack既定化とnext lintの削除

Turbopackは16で安定版になり、既定のバンドラーになりました。前掲のビルド出力でオプション無指定のまま「(Turbopack)」と表示されたとおりです。webpackを使い続けるなら`next build --webpack`のように明示します。注意したいのは、カスタムの`webpack`設定を持ったまま`next build`を走らせると、設定ミスを防ぐ目的でビルドが失敗する仕様になっている点。`--webpack`を付けるか、Turbopack向けの設定へ移すかを先に決めておく必要があります。

`next lint`は削除されました。手元で実行すると、コマンドとして解釈されず「lint」がプロジェクトのディレクトリ名として扱われ、`Invalid project directory provided, no such directory: .../lint`というエラーになります。ESLintやBiomeを直接呼ぶ形に変更が必要で、`next build`もリントを実行しなくなりました。

細かい点ですが、既存プロジェクトに`app`を足す場合は`package.json`の`type`フィールドにも注意してください。`"type": "commonjs"`が入っているとTurbopackのビルドがモジュール形式の不一致で失敗します。`create-next-app`が生成する`package.json`にこのフィールドは無く、手作りのプロジェクトに`npm init`の既定値が残っているときに踏む落とし穴です。

## よくある質問

### appディレクトリとpagesディレクトリは併用できますか？

併用できます。ただし同じURLパスを両方が持つとビルドが失敗します。手元の16.3.0で`app/blog/page.tsx`と`pages/blog.tsx`を同時に置いたところ、`App Router and Pages Router both match path: /blog`というエラーでビルドが停止しました。重複しないパスであれば問題なく共存し、ビルド出力にも`Route (app)`と`Route (pages)`が別の表として並びます。段階移行するときは、移す対象のページをPages Router側から削除してからApp Router側に作る順序を守ってください。

### Pages Routerは廃止されるのですか？

2026年8月時点で廃止の予告はありません。App Routerを安定版にした13.4の公式FAQで、Vercelは`pages/`の開発をバグ修正・改善・セキュリティパッチを含めて複数のメジャーバージョンにわたりサポートすると明言しています。実際、最新安定版16.3.0のドキュメントにもPages Router向けのセクションが残っています。ただし新機能はApp Router側に投入されるため、長期的にはApp Routerへ寄せる前提で計画を立てるのが妥当です。

### App Routerでnext/headは使えますか？

使えません。`app`ディレクトリでは`next/head`が組み込みのSEOサポートに置き換えられており、公式の移行ガイドもそう明記しています。代わりに`page`や`layout`から`metadata`オブジェクトをエクスポートしてtitleやdescriptionを指定します。URLのスラッグに応じてタイトルを変えるなど動的に組み立てる場合は、`generateMetadata`関数をエクスポートしてください。この関数にも動的セグメントの`params`が渡されます。

### page.jsとpage.tsxはどちらで書くべきですか？

どちらでも動きます。公式のAPIリファレンスは`page`に使える拡張子として`.js`・`.jsx`・`.tsx`を挙げており、JavaScriptのプロジェクトなら`app/page.js`、TypeScriptなら`app/page.tsx`という使い分けになります。TypeScriptでも`.ts`ではなく`.tsx`を選ぶ理由は、`page`がJSXを返すためです。JSXを含まない`route`のほうは`.ts`で書きます。なおファイル名`page`の部分は予約語なので変更できません。

### getServerSidePropsはApp Routerでどう書き換えますか？

対応する関数はなく、サーバーコンポーネントの中で直接`await`してデータを取得します。コンポーネントを`async function`として定義し、取得した値をそのまま描画に使う形です。`props`として返す手順は不要になりました。ビルド時に静的パスを列挙していた`getStaticPaths`だけは後継関数があり、`generateStaticParams`という名前に変わっています。なお`fetch`の結果はNext.js 15以降は既定でキャッシュされないため、キャッシュしたい箇所は明示的に指定してください。

## 関連記事

- [Next.js 16とは？ReactベースのWeb開発フレームワーク最新版の概要や主要機能を詳しく紹介](/tech/details/9596/)
- [Next.jsのレンダリング方式｜SSG・ISR・SSR・CSRの違いとApp Routerでの選び方](/tech/details/3791/)
- [React Server Components（RSC）とは？サーバー・クライアントの違いと使い分けを実装例で解説](/tech/details/4003/)
- [SSR・CSR・SSG・ISG・ISRの違いと使い分け｜定義・SEO・速度を比較](/tech/details/2335/)

---

出典: [App Routerとは？Next.jsのファイル規約・動的ルーティング・Pages Routerとの違い](<https://www.issoh.co.jp/tech/details/4026/>)（株式会社一創）
