Web開発フレームワークとして多くの支持を集める Next.js は、バージョン13で新しい App Router がデフォルトのルーティングシステムとして導入されました。
Pages Router と App Router の両方のプロジェクトに関わる中で「どっちの書き方だっけ?」と混同する方もいらっしゃるかと思います。まさに私です!!
特に、ファイル構造に基づいたルーティングの定義方法から始まり、URLの動的な部分の扱い方、さらにはレンダリングの仕組み、そしてAPIからのデータ取得といった、アプリケーション開発の根幹に関わる部分で、Pages Router と App Router には無視できない違いが存在します。
「ごちゃ混ぜになりがちな」ポイントに焦点を当て、Pages Router と App Router の主要な違いを簡単にではありますが備忘録として記載します!
ファイルのルーディングの違い
Pages Router:ファイル名がそのままパスになるシンプルさ
pagesディレクトリ配下に配置した .js
, .jsx
, .ts
, .tsx
ファイルのファイル名が、そのままURLのパスになるというシンプルさです。
例:src/page/about.tsx
⇒ ルーティングは、/about
となります。
App Router:フォルダと特定のファイル名で構造化
App Router はsrc/app
配下にフォルダやファイルを置く事で、ルーティングできます。
ただし、ルーティングに利用するファイル名にpageという特定のファイル名をつけたものが、そのパスに対応するページのコンテンツとして扱われます。
例:src/app/about/page.tsx
⇒ ルーティングは、/about
となります。
App Router を特徴づける「特別なファイル」たち
またApp Routerではpage.tsx以外にも、意味を持つファイルがあります。
app/
├── page.tsx --> ページの中身。これが一番よく使うファイル
├── route.tsx --> APIの定義(page.jsと共存不可)
├── layout.tsx --> 共通の見た目
├── loading.tsx --> 読み込み中の画面
├── error.tsx --> エラー時の画面
├── global-error.tsx --> グローバルエラー画面
├── templete.tsx --> 共通の見た目(リセットされるレイアウト)
├── default.tsx --> デフォルトの画面
└── not-found.tsx --> notFound関数がスローされたときの画面
個人的に驚いたのがnot-found.tsx。このページを用意しておくだけで存在しないURLへのアクセス時に自動的に表示されるようになります。こんなに簡単に実装できてしまうのか、、と感心しました。
レンダリングの違い
Pages Router におけるコンポーネントは、基本的にはクライアントサイドでインタラクティブになることを前提としており、サーバーサイドでのレンダリングは主に初期表示の高速化やSEOのために行われます。useState
や useEffect
といった React のフックは、ページコンポーネント内やその子コンポーネント内で自由に使用できます。
一方でApp Routerのapp/
内のコンポーネントは、明示的に指定しない限り、デフォルトでサーバーコンポーネントとして扱われます。そのためuseState
や useEffect
といったReact のフックは使用できません。クライアント側のアクション、onClickなどのイベントハンドラも使用できません。
そこでApp RouterでCSRにするにはuse client
を記述します。
use client
Server Component と Client Component の境界の宣言です。use client
を宣言したらそのコンポーネントだけではなく、インポートしてるすべても Client Component としてみなされる
動的ルーディング [○○]
ブログやニュースの記事詳細ページのように、URLの一部がユーザーやコンテンツによって変化する「動的なURL」に対応するための仕組みが、Next.js のダイナミックルーティングです。
例えば記事A、記事Bに遷移するリンクがあるとします。

import Link from "next/link";
const linkStyle=`ext-lg font-bold border-b border-primary px-1`
export default function page() {
return (
<div>
<div className="flex gap-6">
<Link href="/post/A" className={linkStyle}>記事Aへのリンク</Link>
<Link href="/post/B" className={linkStyle}>記事Bへのリンク</Link>
</div>
</div>
);
}
リンクそれぞれの遷移先


動的ルーディングにする場合、[slug]
というファイルを作成すれば、post/A
でもpost/B
でも同じテンプレートを使用することができます。
※[ ]のネーミングは任意なのでslug
でなくてもよい
App Routerの場合
/app/post/[slug]/page.tsx
export default aysinc function PostPage({ params }: { params: Promise<{ slug: string }>) {
const {slug}= await params;
return (
<div>
<h1>記事: {slug}</h1>
</div>
);
}
params
を使います。params.slug
に URLの[slug]
部分が入ります。
※ params
でのパラメーター取得がこれまで非同期である必要はありませんでしたが、Next.js 15からは非同期で行うように変更されました。そのため、props
を Promise 型で定義する必要があるようです。
Pages Rouerの場合
/pages/post/[slug].tsx
import { useRouter } from 'next/router';
export default function PostPage() {
const router = useRouter();
const { slug } = router.query;
return (
<div>
<h1>記事: {slug}</h1>
</div>
);
}
useRouter
を使います。router.query.slug
に、URLの [slug]
の部分の値が入ります。
APIデータ取得方法
まさにこのLiberogicコラムでも大活躍しているmicroCMSはNext.jsのようなフレームワークとの相性がよいです。
App Routerの場合
シンプルにfetch
やaysnc
await
を使用するでよいです。
ただし、use client
を宣言したファイルはCSRになるのでaysnc
await
は使えなくなります!
async function getPost() {
const res = await fetch(`https://.../api/data/`);
// エラーハンドリング例
if (!res.ok) {
throw new Error(`Failed to fetch post: ${res.status}`);
}
return res.json();
}
呼び出し先
export default function Example() {
const data = await getPost()
// ... data を使って表示 ...
}
Pages Routerの場合
getStaticProps
を使用し、取得したデータを props
としてページコンポーネントに渡します。
export async function getServerSideProps(context) {
// context.req, context.res などにアクセス可能
const res = await fetch(`https://.../api/data/`, {
headers: { Cookie: context.req.headers.cookie } // 例: Cookieを渡す
});
const data = await res.json();
return {
props: {
data,
},
};
}
呼び出し先
export default function Example({ data }) {
// ... data を使って表示 ...
}
二つのルーターを理解し、Next.js を使いこなそう!
私の場合、最初にNext.jsを触った案件はApp Routerでした。
その後に別の案件でPages Routerを触り、「新規のページを作成するにはファイル名 index.tsxとpage.tsxどっちだっけ??」と、なりました。
今回の内容はNext.jsのほんの一部ですが、改めてApp RouterとPages Rouerの違いなどを調べることで自分の中でも整理できました。
個人的にはApp Routerの書き方が分かりやすくて好きなのですが、Pages Routerの案件でもしっかり対応できるようにしたいです。
Next.js をより深く理解し案件や制作物によってそれぞれのルーターを使い分けられるようになるのが理想ですね!
マークアップを中心に、JavaScriptやReact、Next.jsを使ってフロントエンドの開発をやっています。自分が関わったサイトが無事に公開されると嬉しかったりします!趣味はギターを弾くこと。コードは書くのも弾くのもどっちも楽しいです!
ひらっち
フロントエンドエンジニア/2022年入社