Next.js の App Router では、フォルダとファイルを置くだけでページ(URL)が作られます。ルーティングの設定を別に書く必要はありません。この記事では、App Router を使ったページの作り方を基礎から解説します。page.tsx の役割、フォルダ構成と URL の対応、共通レイアウト、<Link> によるページ遷移、そして [id] のような動的なページの作り方まで、手を動かしながら理解できるように順番に説明します。なお、ここでは Next.js 13 以降で標準になった app ディレクトリ(App Router)を前提にしています。
目次
page.tsx がページになる
App Router では、app ディレクトリの中に置いた page.tsx(または page.js)というファイルが、そのフォルダに対応する URL のページになります。まずはトップページを作ってみましょう。app/page.tsx がサイトのルート(/)に対応します。
export default function Home() {
return (
<main>
<h1>トップページ</h1>
<p>ようこそ!</p>
</main>
);
}
ポイントは、ページになるコンポーネントを export default で書き出すことです。この page.tsx を置くだけで、開発サーバー(npm run dev)を起動すると http://localhost:3000/ にこのページが表示されます。特別なルーティング設定は不要です。
フォルダ名がそのまま URL になる
新しいページを追加したいときは、app の中にフォルダを作り、その中に page.tsx を置きます。フォルダ名がそのまま URL のパスになります。たとえば「会社概要」ページを /about に作るなら、次のようにします。
export default function About() {
return (
<main>
<h1>会社概要</h1>
</main>
);
}
フォルダの階層をそのまま URL に対応させられるので、構成が直感的です。いくつか例を挙げると、次の表のようになります。
| ファイルの場所 | 対応する URL |
|---|---|
app/page.tsx | / |
app/about/page.tsx | /about |
app/blog/page.tsx | /blog |
app/blog/first/page.tsx | /blog/first |
ここで注意したいのは、ページとして表示されるのは page.tsx という名前のファイルだけという点です。同じフォルダに Button.tsx のような別のコンポーネントを置いても、それが URL になることはありません。フォルダに page.tsx が無ければ、そのパスはページとして存在しない扱いになります。
layout.tsx で共通の枠を作る
ヘッダーやフッターのように、全ページで共通の見た目を layout.tsx にまとめられます。app/layout.tsx はすべてのページを包む「一番外側の枠」です。App Router では、このルートレイアウトは必須で、html と body タグをここに書きます。
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ja">
<body>
<header>共通ヘッダー</header>
{children}
<footer>共通フッター</footer>
</body>
</html>
);
}
children の位置に、各ページの page.tsx の内容が差し込まれます。つまり、どのページを開いてもヘッダーとフッターは共通で表示され、真ん中だけがページごとに切り替わります。特定のフォルダ内だけで共通にしたいレイアウトは、そのフォルダに layout.tsx を置けば、その配下のページにだけ適用されます。
Link コンポーネントでページを移動する
ページ間の移動には、next/link の <Link> コンポーネントを使います。通常の <a> タグでもリンクはできますが、<Link> を使うとページ全体を再読み込みせずに切り替わるため、表示が速く、入力中の状態なども保たれます。
import Link from 'next/link';
export default function Home() {
return (
<nav>
<Link href="/">ホーム</Link>
<Link href="/about">会社概要</Link>
<Link href="/blog">ブログ</Link>
</nav>
);
}
href に移動先の URL を指定するだけです。書き方は <a> とほとんど同じですが、内部リンクには <Link> を使うのが Next.js の基本と覚えておきましょう。外部サイトへのリンクは、これまでどおり <a> で問題ありません。
[id] で動的なページを作る
ブログ記事のように「URL の一部が可変」なページは、フォルダ名を [ ](角括弧)で囲んで作ります。たとえば app/blog/[id]/page.tsx と置くと、/blog/1 や /blog/hello など、/blog/ に続く任意の値を1つのページで受け取れます。この可変部分は params から取り出します。
export default async function BlogPost({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
return (
<main>
<h1>記事ID: {id}</h1>
</main>
);
}
フォルダ名 [id] の id が、そのまま params のプロパティ名になります。/blog/5 にアクセスすれば id は '5' になり、この値をもとにデータベースや API から該当記事を取得する、という使い方が一般的です。なお Next.js 15 以降では params が Promise になったため、上のように await で受け取ります(それ以前のバージョンでは直接 params.id と書けます)。
ページが表示されないとき
作ったはずのページが 404 になる場合、いくつか定番の原因があります。まず確認したいのがファイル名です。ページになるのは page.tsx という決まった名前だけで、index.tsx や Page.tsx(大文字始まり)ではページとして認識されません。App Router では index ではなく page である点に注意してください。
次に多いのがフォルダの場所です。ページ用のフォルダは必ず app の中に置きます。app の外に作っても URL にはなりません。また、コンポーネントを export default で書き出しているかも確認しましょう。名前付きエクスポートだけだと、Next.js がページとして読み込めずエラーになります。
まとめ
Next.js の App Router では、app ディレクトリにフォルダを作り、その中に page.tsx を置くだけでページが作られます。フォルダ名がそのまま URL になり、共通の枠は layout.tsx、ページ間の移動は <Link>、URL の一部が可変なページは [id] フォルダで実現します。ページが表示されないときは、ファイル名が page.tsx か、app の中に置いているか、export default しているかを確認しましょう。この基本さえ押さえれば、複数ページのサイトを素早く組み立てられます。