Next.js Catch-all Routesで複雑なURL構造を簡単に実現する方法!初心者向け解説
生徒
「先生、Next.jsでブログみたいに階層が深いURLを作りたいです。例えば /blog/2026/02/15 みたいなURLです。」
先生
「その場合はCatch-all Routes(キャッチオールルート)を使うと便利です。URLの階層をまとめて1つのページコンポーネントで処理できます。」
生徒
「キャッチオールルートってどう書くんですか?なんだか難しそうです。」
先生
「実はとても簡単です。Next.jsではブラケットと三点リーダー(...)を使ってファイル名を作るだけです。順番に見ていきましょう。」
1. Catch-all Routesとは?
Catch-all Routes(キャッチオールルート)とは、1つのページコンポーネントで複数のURLパスをまとめて処理できる仕組みです。例えば /blog/2026/02/15 や /blog/2026/02 など、階層が違うURLでも1つのページで対応できます。Next.jsではファイル名に [...slug].js のように書きます。
2. 基本的なCatch-allの書き方
まずは単純な例です。pagesフォルダ内に [...slug].js を作ります。
import { useRouter } from "next/router";
export default function CatchAllPage() {
const router = useRouter();
const { slug } = router.query;
return (
<div>
<h1>キャッチオールルートのデモ</h1>
<p>URLのパス: {slug ? slug.join("/") : "トップページ"}</p>
</div>
);
}
3. Optional Catch-all Routesの使い方
Optional Catch-all Routes(オプショナルキャッチオール)ではURLが空でもアクセスできるようになります。ファイル名は [[...slug]].js と書きます。
import { useRouter } from "next/router";
export default function OptionalCatchAll() {
const router = useRouter();
const { slug } = router.query;
return (
<div>
<h1>オプショナルキャッチオールのページ</h1>
<p>URLパス: {slug ? slug.join("/") : "トップページ"}</p>
</div>
);
}
4. 複数階層のブログ記事に対応する例
ブログの記事を年月日で整理する場合もCatch-all Routesが便利です。
import { useRouter } from "next/router";
export default function BlogPage() {
const router = useRouter();
const { slug } = router.query;
return (
<div>
<h1>ブログ記事ページ</h1>
{slug && slug.length >= 3 ? (
<p>記事の日付: {slug[0]}年/{slug[1]}月/{slug[2]}日</p>
) : (
<p>記事一覧ページ</p>
)}
</div>
);
}
5. パラメータを使った動的ページ生成
Next.jsのCatch-all Routesは動的ルーティングと組み合わせると便利です。例えば、記事IDやカテゴリをURLに含める場合です。
import { useRouter } from "next/router";
export default function ArticlePage() {
const router = useRouter();
const { slug } = router.query;
return (
<div>
<h1>記事ページ</h1>
<p>カテゴリ: {slug ? slug[0] : "なし"}</p>
<p>記事ID: {slug && slug[1] ? slug[1] : "なし"}</p>
</div>
);
}
6. LinkコンポーネントでCatch-allを使う
Next.jsの Link コンポーネントを使ってCatch-allルートに遷移する方法です。
import Link from "next/link";
export default function Home() {
return (
<div>
<h1>ホームページ</h1>
<Link href="/blog/2026/02/15">
<a>2026年2月15日のブログへ</a>
</Link>
</div>
);
}
7. サーバーサイドでのCatch-all Routes
Next.jsではCatch-all Routesを使ってサーバーサイドでデータを取得することもできます。
export async function getServerSideProps(context) {
const { slug } = context.params;
return {
props: {
pathSegments: slug || [],
},
};
}
export default function SSRPage({ pathSegments }) {
return (
<div>
<h1>サーバーサイドレンダリングページ</h1>
<p>URLパス: {pathSegments.join("/")}</p>
</div>
);
}
まとめ
今回はNext.jsのCatch-all Routes(キャッチオールルート)について詳しく学びました。Catch-all Routesは、複数階層のURLを1つのページコンポーネントでまとめて処理できるNext.jsの便利な機能で、ブログやニュースサイトのように階層構造が複雑なURL設計にも最適です。具体的には、ブラケットと三点リーダーを使った [...slug].js や [[...slug]].js のファイル名で実装できます。
通常のCatch-all RoutesではURLの階層が必須で、例えば /blog/2026/02/15 のようにアクセスするとURLパスが配列で取得できます。一方でOptional Catch-all RoutesではURLが空でもアクセス可能で、トップページや一覧ページの処理を1つのコンポーネントで統一でき、コードの冗長さを避けることができます。また、ブログ記事の年月日形式やカテゴリとIDを含む動的ページも、Catch-all Routesと組み合わせることで柔軟に生成可能です。
Next.jsの Link コンポーネントと組み合わせれば、階層が深いページへの遷移も簡単に実装でき、ユーザー体験を損なうことなく直感的なナビゲーションが可能になります。さらにサーバーサイドレンダリング(SSR)でもCatch-all Routesは有効で、getServerSideProps を利用してURLパスを取得し、サーバー側で必要なデータをフェッチしてレンダリングすることもできます。
このようにCatch-all Routesを理解して使いこなすと、Next.jsでの動的ルーティングの設計が格段に効率的になり、コードの再利用性や保守性も向上します。また、Optional Catch-all Routesや動的パラメータを組み合わせることで、トップページ、一覧ページ、詳細ページなど複数の画面を1つのコンポーネントで管理でき、SEO対策としても階層構造を整理してURL設計がしやすくなります。
実際に使う際のポイントは以下の通りです。まず、Catch-all Routesはブラケットと三点リーダーのファイル名ルールを正しく使うこと、次に router.query.slug を確認してURLパスを配列で受け取り、必要に応じてjoinで文字列化して表示することです。また、Optional Catch-all Routesを使う場合は、slugがundefinedの場合も考慮して「トップページ」や「一覧ページ」と表示する条件分岐を組み込みます。さらにLinkコンポーネントで階層の深いページへの遷移を実装し、サーバーサイドレンダリングでは context.params.slug を取得してデータを処理することが重要です。
これらを組み合わせることで、ブログやECサイト、ニュースサイトなど、複雑なURL構造を持つWebアプリケーションでもNext.jsの柔軟なルーティング機能を最大限に活用できます。Catch-all RoutesはURL設計の自由度を大きく広げるため、Next.jsの動的ルーティングの理解には欠かせない重要なテクニックです。
生徒
「先生、Catch-all Routesって複数階層のURLを一気に処理できるんですね。Optionalもあるのでトップページも同じコンポーネントで作れるんですね。」
先生
「そうです。例えばブログの年月日形式やカテゴリ付き記事でも、1つのページで処理できます。router.query.slugで配列を受け取り、条件分岐を使えば一覧ページや詳細ページを柔軟に表示できます。」
生徒
「Linkコンポーネントと組み合わせれば、ユーザーがクリックしても正しく遷移できるんですね。」
先生
「その通りです。またサーバーサイドレンダリングでもCatch-all Routesは有効なので、context.params.slugを使ってサーバー側でデータを取得することもできます。これでSEO的にも階層構造が整理され、効率よくWebページを生成できます。」
生徒
「なるほど。Catch-all RoutesとOptionalを理解して組み合わせれば、Next.jsで複雑なURLでも簡単に管理できるんですね。」
先生
「その通りです。動的パラメータ、Linkコンポーネント、SSRも組み合わせれば、柔軟で保守性の高いWebアプリケーションが作れます。まずは実際にコードを書いて動作を確認することが大切です。」
import { useRouter } from "next/router";
import Link from "next/link";
export default function DemoPage() {
const router = useRouter();
const { slug } = router.query;
return (
<div>
<h1>Catch-all Routesデモ</h1>
<p>URLパス: {slug ? slug.join("/") : "トップページ"}</p>
<Link href="/blog/2026/02/15">
<a>ブログ2026年2月15日へ</a>
</Link>
</div>
);
}