ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
この記事の要点
- フォルダが URL のセグメントになり、
page.tsxを置いた時点でそのパスが公開される。フォルダを作っただけでは URL にならない。 - 角かっこで囲んだフォルダ名が動的セグメント。
[slug]が 1 階層、[...slug]が全階層、[[...slug]]は省略可能。 - バージョン 16 では
paramsとsearchParamsが Promise。必ずawaitしてから中身を取り出す。 - 丸かっこで囲んだ
(group)は URL に出ない整理用フォルダ。アンダースコア始まりの_folderはルーティング対象から外れる。 - ページ間の移動は
next/linkのLink。先読みとクライアント遷移が効く。
App Router のルーティングは「フォルダの形がそのまま URL の形になる」という単純な規則で成り立っています。ルーティング設定ファイルは存在せず、どんな URL が生えているかはディレクトリツリーを見れば分かります。この記事では、その対応関係と、実務でよく使う動的セグメント・整理用フォルダまでを押さえます。
1フォルダが URL になる
基本の規則は 2 つだけです。
- フォルダが URL のセグメント(
/で区切られた 1 区画)を定義する page.tsxを置いたフォルダだけが、外部からアクセスできる URL になる
裏を返すと、フォルダを作っただけでは URL は生えません。これは意図的な設計で、コンポーネントやユーティリティを route と同じ場所に置いても、うっかり公開されてしまう心配がないようになっています。
| ファイルの場所 | 対応する URL |
|---|---|
app/page.tsx | / |
app/blog/page.tsx | /blog |
app/blog/authors/page.tsx | /blog/authors |
app/blog/utils.ts | (URL にならない。同じ場所に置いても安全) |
ページの実体は、React コンポーネントを default でエクスポートするだけです。
// app/blog/page.tsx
export default function Page() {
return <h1>ブログ一覧</h1>
}
2動的セグメントで URL に値を埋める
記事 ID や商品コードのように値が可変な URL は、フォルダ名を角かっこで囲んで表現します。これを動的セグメントと呼びます。
| フォルダ | マッチする URL | 用途 |
|---|---|---|
app/blog/[slug]/page.tsx | /blog/hello | 1 階層ぶんの値 |
app/shop/[...slug]/page.tsx | /shop/clothing、/shop/clothing/shirts | 階層の深さが決まらないカテゴリなど |
app/docs/[[...slug]]/page.tsx | /docs と、その配下すべて | 省略も許したいドキュメント階層 |
受け取った値は params という props に入ります。ここがバージョン 16 での最大の変更点で、params は Promise になりました。同期的に params.slug と書くとエラーになります。
// app/blog/[slug]/page.tsx
export default async function BlogPostPage({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params // 必ず await する
const post = await getPost(slug)
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
)
}
TypeScript を使っている場合は、型を手で書く代わりにグローバルヘルパーの PageProps が使えます。この型は next dev や next build の実行時に自動生成され、インポートは不要です。
// app/blog/[slug]/page.tsx
export default async function Page(props: PageProps<'/blog/[slug]'>) {
const { slug } = await props.params
return <h1>記事: {slug}</h1>
}
3クエリ文字列を読む
?page=2 のようなクエリは searchParams で受け取ります。これも Promise です。
export default async function Page({
searchParams,
}: {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const { page } = await searchParams
// page を使ってデータを取りに行く
}
クエリはリクエストが届いて初めて確定する値なので、これを読むとそのページはリクエスト時に描画されることになります。使い分けの目安は次のとおりです。
searchParams を使うページャや絞り込みのように、クエリの値を使ってサーバー側でデータを取りに行くとき。
useSearchParams を使うすでに読み込み済みの一覧をブラウザ側だけで絞り込むなど、クライアントで完結するとき。
4URL に出ないフォルダ
アプリが育つと「URL は変えたくないが、コードはグループごとに分けたい」という要求が出てきます。これに応えるのが 2 種類の特別なフォルダ名です。
(group) は URL を変えずにレイアウトを分けるため、_folder は確実にルーティングから外すために使う。ルートグループ (group) はフォルダ名を丸かっこで囲む書き方です。URL には現れないので、app/(marketing)/about/page.tsx は /about になります。グループごとに layout.tsx を置けるため、「公開ページと管理画面でヘッダーを変えたいが、URL の階層は増やしたくない」という場面で使います。
プライベートフォルダ _folder はアンダースコアで始めるフォルダで、そのフォルダと配下すべてがルーティングから除外されます。前述のとおり同居ファイルは元々 URL になりませんが、意図を明示したいときや、将来 Next.js が追加する予約ファイル名と衝突させたくないときに有効です。
5ページ間を移動する
画面遷移には next/link の Link コンポーネントを使います。見た目は a タグですが、リンク先の先読みとクライアント側での遷移が働き、ページ全体の再読み込みが起きません。
import Link from 'next/link'
export default async function Posts() {
const posts = await getPosts()
return (
<ul>
{posts.map((post) => (
<li key={post.slug}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}
素の a タグを使うとフルリロードになり、レイアウトの状態もスクロール位置も失われます。外部サイトへのリンク以外は Link を使うのが原則です。ボタンのクリック処理の中などから遷移したい場合は useRouter を使いますが、まずは Link で足りないかを検討してください。
6特殊な配置パターン
頻度は下がりますが、覚えておくと設計の幅が広がる規則もあります。
| 記法 | 意味 | 典型的な用途 |
|---|---|---|
@folder | 名前付きスロット(並行ルート) | サイドバーと本文を別々に描画する |
(.)folder | 同じ階層のルートを差し込む | 一覧の上に詳細をモーダルで重ねる |
(..)folder | 親階層のルートを差し込む | 親の子ページをオーバーレイ表示する |
(...)folder | ルート直下から差し込む | 任意のページを現在の画面内に出す |
並行ルートを使う場合、バージョン 16 からはすべてのスロットに default.tsx が必須になりました。無いとビルドが失敗します。従来の挙動に合わせるなら、notFound() を呼ぶか null を返すファイルを置きます。
// app/@modal/default.tsx
export default function Default() {
return null
}
7つまずきやすいところ
- フォルダを作ったのに 404 になる:
page.tsxが無いだけです。フォルダは URL を作るが、公開するのはpageかrouteの役目です。 params.slugが undefined になる:await paramsを忘れています。バージョン 15 まではそのまま読めたため、古い記事のコードが混ざると起きがちです。- ルートグループを重ねすぎる:URL に出ないぶん構造が見えにくくなります。レイアウトを分ける目的がないなら普通のフォルダで十分です。
- 同じ階層に
page.tsxとroute.tsを置く:競合してビルドが通りません。API は別のパスに切り出します(Route Handlers で API を作る)。
URL の骨格ができたら、次はその周りを取り囲む共通レイアウトと、読み込み中・エラー時の表示を担当する特殊ファイルを見ていきます。
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 Spring Frameworkのアノテーション一覧
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- PHPでのファイルアップロード方法|multipart/form-dataと$_FILES 2026-08-07 17:15:57
- PHP $_SERVERとは|DOCUMENT_ROOT・PHP_SELFなど主な要素 2026-08-07 17:15:57
- Scratchのアカウントの作り方|メールアドレスとユーザー名の登録手順 2026-08-07 17:15:57
- djangoにおけるMVCアプリケーション実装例 2026-08-07 17:15:57
- Bluetoothとは|仕組み・BLEとClassicの違い・用途 2026-08-07 17:15:57
- Spring Bootのテスト入門|@SpringBootTestとJUnitでの単体・結合テスト 2026-08-07 17:15:57
- Java とは?言語仕様・JVM・主要フレームワーク一覧 2026-08-07 17:15:56
- インストール方法(Windows版) 2026-08-07 17:15:56
- APIキー取得方法 2026-08-07 17:15:56
- 【PHPフレームワーク】Laravelの使い方 2026-08-07 17:15:56
- Scratch 作品の公開方法 2026-08-07 17:15:56
- Google OAuth 2.0 認証の実装方法 2026-08-07 17:15:56
- データベースとは?RDB / NoSQL / SQL の基礎 2026-08-07 17:15:56
- インストール(eclipseプラグイン) 2026-08-07 17:15:56
- Spring Frameworkの使い方 2026-08-07 17:15:56
コメントを削除してもよろしいでしょうか?