AI コーディングアシスタントに Next.js(Reactベースのフレームワーク)のコードを書かせたら、動かないコードが返ってきた経験はないでしょうか。ChatGPT や Claude、あるいは古いチュートリアルの通りに getServerSideProps を App Router のプロジェクトに貼り付けて、ビルドエラーになる。これは AI の幻覚(hallucination、事実と異なる内容を生成する現象)ではなく、Next.js の公式ドキュメント自体が二つの矛盾した答えを同時に公開していることが原因です。
この記事は、Next.js のバージョンアップやリファクタリングに AI ツールを使っているエンジニア向けに、この落とし穴の正体と回避方法を整理します。
何が起きるか
Next.js には Pages Router(pages ディレクトリベースの従来型ルーティング)と App Router(app ディレクトリベースの新しいルーティング)という、互換性のない二つのルーティング方式が存在します。
どちらの公式ドキュメントも nextjs.org 上で現在も公開されており、検索エンジンにも両方インデックスされています。ページ側に「これは古い方式です」という警告バナーは付いていません。
そのため、AI アシスタントが Pages Router 時代の getServerSideProps(サーバー側でデータ取得を行う関数)をコード例として返し、それを App Router 構成のプロジェクトに貼り付けると、Next.js はビルド時にエラーを出します。AI の回答自体は「間違い」ではなく、「別のルーターのための正解」だったというのが実態です。
なぜ起きるか
原因を段階的に分解すると、三つの層に分かれます。
第一に、Next.js 自体が過渡期の設計を採用しています。App Router は Pages Router を置き換える新方式として導入されましたが、後方互換性のため Pages Router は現在も削除されていません。結果として二つの「正しい」データ取得方法が並存しています。
第二に、AI モデルの学習データには両方のドキュメントとチュートリアルが混在しています。モデルは文脈から「このプロジェクトがどちらのルーターを使っているか」を明示的に推論できないと、学習データ中で頻度の高いパターンや、質問文に近い表現を優先して返してしまう傾向があります。
第三に、検索エンジンやドキュメント検索も「どちらの方式のページに着地したか」を利用者に伝えません。URL を見れば pages/ か app/ かの区別はできますが、コピー&ペーストする側がその区別を意識していないと、ミスマッチに気づかないまま実装が進みます。
自分のプロジェクトが該当するかの確認方法
対策の前に、自分のプロジェクトがどちらの方式を使っているかを確認します。
- ディレクトリ構成の確認: プロジェクトルートに
app/ディレクトリがあれば App Router、pages/ディレクトリのみであれば Pages Router です。両方存在する場合は移行途中のハイブリッド構成です next.config.jsの確認: App Router 特有の設定項目(experimental.appDirなど、バージョンによって異なる)が入っていないか確認します- バージョンの確認:
package.jsonのnextの値を見て、13.4 以降であれば App Router が安定版として利用可能です。実行中のバージョンはnpx next --versionで確認できます - ファイル名の確認:
getServerSidePropsやgetStaticPropsを使っているファイルがpages/配下にあるか、app/配下にあるかをgrepで洗い出します
grep -rl "getServerSideProps\|getStaticProps" ./app ./pages 2>/dev/nullこのコマンドで app/ 側にヒットが出た場合、Pages Router 用のコードが App Router に混入している可能性が高いです。
対策の手順
1. AI にルーターの前提を明示する
プロンプトの冒頭で「このプロジェクトは Next.js の App Router(app ディレクトリ)を使っています」と明示します。ルーター名を書かずに質問すると、モデルは学習データの頻度に基づいて Pages Router の答えを返す可能性があります。
2. コード生成後に対応表で検算する
Pages Router と App Router では、同じ機能でも呼び方が異なります。代表的な対応関係を把握しておくと、AI の回答を検算できます。
| 目的 | Pages Router | App Router |
| サーバー側データ取得 | getServerSideProps | async Server Component 内で fetch |
| 静的生成 | getStaticProps | fetch のキャッシュオプションで制御 |
| ルーティング単位 | pages/foo.tsx | app/foo/page.tsx |
3. 公式移行ガイドを一次情報として使う
Next.js 公式には App Router Migration という専用の移行ガイドがあります。AI に「この移行ガイドに基づいて変換して」と指示すると、回答の根拠を一次ソースに固定できます。
4. AI に出典を求める設計にする
コード変換や技術質問を AI に投げる際、「根拠となるドキュメントの節を明示して」と付け加えるだけでも、モデルが自身の記憶だけで答えを埋めるリスクを減らせます。回答に出典が付かない場合は、その部分を鵜呑みにしないという運用ルールを持つことが有効です。
5. MCP や社内ナレッジベース連携で知識源を固定する
MCP(Model Context Protocol、AI とデータソースを接続する規格)を使って、社内ドキュメントや特定バージョンの公式ドキュメントのみを AI の参照先に絞り込む構成も検討に値します。参照範囲を「Pages Router のページのみ」「App Router のページのみ」のように分離できれば、混在による誤答を構造的に減らせます。実際に、クロール対象を nextjs.org の特定パス(Pages Router 用ドキュメント、App Router 用ドキュメント、移行ガイド)に絞り込み、各回答に出典チップを付けて「知識ベースに情報がない場合は推測せず不明と答える」設計にした事例もあります。この場合、クロールの Max depth(何階層先までリンクをたどるか)の設定値が浅いと、必要なページ数が集まらずナレッジベースが不完全になる点にも注意が必要です。
まとめ
Next.js の Pages Router と App Router は、どちらも公式に生きているドキュメントであり、AI モデルにとってはどちらも「正解」に見えます。
矛盾は Next.js の設計上の過渡期に起因するものであり、AI の欠陥だけが原因ではありません。
次に AI へ Next.js のコードを依頼するときは、プロンプトにルーター名を明示し、生成されたコードが app/ と pages/ のどちらの慣習に沿っているかを grep や対応表で検算してみてください。
出典の提示を求める運用や、参照範囲を絞ったナレッジベース連携も、この種の食い違いを減らす具体的な一歩になります。