【Next.js】App RouterとPages Routerの違いについて
2025年2月5日
こんにちは!オルトロボでエンジニアとして働くSです。
本日はReactフレームワーク「Next.js」の「App Router」について、以前の機能と比較しながら解説いたします。
Next.js 13.4から「App Router」というルーティング機能が安定版(Stable)としてリリースされるとともに、それ以前のVerについては「Pages Router」と呼称されるようになりました。
この二つはファイル構成や機能など大きな相違点があり、公式ドキュメントでもそれぞれ別々のドキュメントが用意されています。
(サイドバー左上のアイコンからドキュメントの切り替えが出来るようになっています)
本記事では以下のような方々を読者と想定して、App Routerの機能の説明に加え、Pages Routerとの違いやメリット・デメリットについて解説していきます。
・Next.js 13以前のVerの使用経験があるが、「App Router」は未経験の方
・Vue.js等のReactフレームワークは知っているが、Next.jsについて知りたい方
目次
1.機能比較
詳細に入る前に、まず各機能の違いについての概略を下記表にまとめました。
機能 | Pages Router | App Router |
---|---|---|
ルーティング方式 | ファイルベース | ディレクトリベース |
レンダリング | SSG・SSR・CSR | SSG・SSR・CSR +Streaming |
Data Fetch | サーバーサイド ・getStaticProps ・getServerSideProps クライアントサイド ・useEffect Hooks | サーバーサイド ・Server Componentsでの非同期処理(fetch APIの呼び出し等) クライアントサイド ・useEffect Hooks |
fetchしたデータの受け渡し方法 | props | 各Componentでfetch |
Component | Client Component | Server Component Client Component |
SEO対応 | next/headコンポーネント | Metadata |
概略を把握したところで、次章より各機能の詳細を解説します。
2.ルーティング方式
Pages Routerでは、pagesディレクトリ配下にファイルを配置するとそのファイル名で自動的にルートが生成されるという、「ファイルベース」のルーティングシステムでした。
一方App Routerでは、appディレクトリ配下のディレクトリ内に「page1」というファイルを配置するとディレクトリ名でルートが生成されるという、「ディレクトリベース」のルーティングシステムとなります。
具体的には以下のようなURLの構造になります。
//Pages Routerのフォルダ構造
pages
├─ index.js // https://www.example.com
├─ blog.js // https://www.example.com/blog
└─ dashboard
└─ user.js // https://www.example.com/dashboard/user
//App Routerのフォルダ構造
app // https://www.example.com
├─ page.js
├─ blog // https://www.example.com/blog
│ └─ page.js
└─ dashboard
└─ user // https://www.example.com/dashboard/user
└─ page.js
詳細は省きますが、App Routerではファイル名を特定のフォーマットにすることで、
Dynamic routesやルートのグループ化、private folders(ルーティングから除外したいフォルダの定義)を設定することが出来ます。
また、上記の基本的なファイルの他、App Routerでは役割ごとの特別なファイルが用意されており、以下にその一部をご紹介します。
- layout ルート共通のUI(例:ヘッダー、サイドバー)
- loading ローディング中のUI(例:スケルトン、ローディングスピナー)
- error エラー時のUI
- not-found not-Found時のUI
- middleware Request時に実行されるコードの定義
- route APIエンドポイント
3.レンダリング
次に、それぞれのレンダリング方式の違いについて解説いたします。
Pages RouterではData Fetchメソッドである「getStaticProps」「getServerSideProps」を定義することで、SSG・SSRの設定を行うことが出来ます。
一方App Routerでは、後述する「Client Component」「Server Component」を使い分けることで大きくCSRかサーバーサイドでのレンダリングかが分かれます。
また、サーバーサイドでのレンダリングではさらに、Data Fetchのオプションでキャッシュするかしないかを設定でき、これによりSSG・SSRを使い分けることが出来ます。
また、App Routerでは上記の基本的なレンダリング方法のほか、子Componentを<Suspense>でラップすることで、ローディング中にfallbackUiでスケルトンやスピナーを表示させるStreamingなど、UXの向上に繋がる機能を備えています。
4.Data Fetch
次にData Fetchについてですが、クライアントサイドに関しては
Pages RouterもApp Routerも、従来通り「useEffect」等のHokksやTanStack Queryなどのライブラリで行います。
サーバーサイドに関しては、Pages Routerには「getStaticProps」「getServerSideProps」という特別なメソッドが用意されていました。
一方、App Routerでは Server Components内に直接fetch等の非同期処理を書くことができるため、上記二つのメソッドは廃止されました。
それに加えApp RouterはReact 8から導入された「Server Actions」を使用できるため、ServerComponent・ClientComponentどちらからでもサーバーサイドの処理を呼び出すことも出来ます。
Server Actionsについては現状Next.jsは早い段階で取り入れていますが、今後他のFWでも対応していく可能性は高いと思われます。
5.fetchしたデータの受け渡し方法
次にfetchしたデータのcomponent間の受け渡し方法について。
Pages Routerでは親componentで取得したデータを配下のcomponentへ渡すには、propsを通した、いわゆるプロップス バケツリレーで行う必要がありました。
一方、App Routerでは各componentで直接fetch出来るので、そもそもデータを受け渡す必要がありません。
ここで、同じルート内で同じfetchが複数箇所にあった場合に不要なrequestが発生するのではないかと疑問に思われるかもしれませんが、Request Memoization(同一リクエストの重複排除) という機能により、親と子で同じ内容をそれぞれfetchしても1回しか実行されないようになっています。
この機能で一つ注意が必要なのは、同一URL・同一オプションを指定しないと異なるfetchと見なされてしまいます。
6.Component
次にComponentについて、Pages RouterではそもそもComponentは一種類しかないので、App Routerについてのみの解説となります。
App RouterのComponentは、Server ComponentとClient Componentの2種類あり、初期コンポーネントはServer Componentが設定されています。
Server Componentはfetchなどのサーバーサイドの処理を実行することが出来、レンダリングもサーバーで行われます。
サーバー側で直接非同期処理がかけるため、APIエンドポイントを用意する必要がなかったり、通信回数を減らすことが出来ます。
また、サーバー側でのコンパイル時にjsがバンドルされるためファイルサイズが小さくなるというメリットもあります。
Client ComponentはHooksやイベントハンドラ、localStorageなどのブラウザ側APIの使用などクライアントサイドの処理を実行することが出来、レンダリングもクライアント側で行われます。
デフォルトではServer Componentが設定されていますが、ファイルの1行目に”use client”と定義することでClient Componentとなります。
このように実装したい処理によって2種のComponentを使い分けることで、Component毎に最適な方法を選択することが出来ます。
注意点として、2種のComponentにはClientBoundary(境界線)というものがあり、Client Componentの子コンポーネントはClient Componentになる、という性質があります。
これを回避するには、親のClient ComponentのchildrenなどのpropsにServer Componentsを渡す、Compositionパターンという手法を取る必要があります。
7.SEO対応
最後に、SEO対応について簡単に解説いたします。
Pages Routerではnext/headからを呼び出し、head要素を管理する必要がありました。
一方App Routerでは、page.tsxかlayout.tsxで以下のように実装するだけでSEOタグを実装することが出来るようになりました。
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'hoge',
description: 'fuga',
}
8.メリット・デメリット
最後にPages Routerと比較した際の、App Routerのメリット・デメリットをまとめたいと思います。
- メリット
-
・ファイルサイズの減少
Server Componentの解説でも触れましたが、Server Componentはサーバー側でコンパイルする際、jsもバンドルされるためファイルサイズが小さくなります。
基本はServer Componentを使用し、クライアントの処理が必要なものだけClientComponentとして切り分けることで、ファイルサイズを抑えることが出来ます。・Server Actionsを使える
Server Componentでもサーバーサイドの処理を書くことが出来ますが、Server Actionsで、サーバーサイドの処理を書いてそれぞれのComponentから呼び出すことで、可読性の向上やコード量の減少につながります。 - デメリット
-
・学習やキャッチアップのコストが高い
App Routerはリリースされてまだ日が浅いということもあり、ファイル構成のベストプラクティスやエラー解消のナレッジが多くありません。
ネットで探しても見つからなかったり、あっても英語の記事しかないなど、課題の解決に多くの時間を取られる可能性があります。・UIコンポーネントライブラリの対応が追いついていない
Next.jsでは、Material-UIやChakra UIなどの各種UIライブラリを使用できますが、それらがApp Routerで出来るかは個別に検証していく必要があります。
実際、私はAnt Designで作成されたPages RouterプロジェクトのApp Routerへの移行を行いましたが、Server ComponentでAnt Designを使おうとするとコンパイル時にエラーが起きてしまい、結局解決できずに泣く泣くClient Componentを使用したケースがありました。
9.まとめ
以上、App RouterとPages Routerの違いについて解説をさせていただきましたがいかがでしたでしょうか。
App Routerはまだナレッジが少ないため、開発に当たり予期せぬエラー等にぶつかることも多いでしょうが、本記事がその際の一助になれば幸いです。
弊社では、システム開発による課題解決からRPAやBIツールによる業務効率化・開発支援も行っています。
業務効率化・DX化、システム開発等でお困りごとがございましたらお気軽にお問い合わせください。
最後までお読みいただき、誠にありがとうございました!
- 「page」ファイルの拡張子は、「js」のほか「jsx」「tsx」などの拡張子もサポートしています。 ↩︎