Next.js入門|App Routerの基本・SSR/SSGの違い・最初のアプリを作る手順
目次
Next.jsとは何か
Next.jsは、ReactをベースにしたWebアプリケーションフレームワークです。Vercelが開発・メンテナンスしており、2024年時点でReactエコシステムにおける最も普及したフレームワークのひとつです。
ReactだけとNext.jsの違い:
Reactは「UIを作るためのライブラリ」であり、ルーティングやサーバーサイドレンダリングなどの機能は自分で設定する必要があります。一方Next.jsはこれらの機能がすべてビルトインで提供されます。
| 機能 | React単体 | Next.js |
|---|---|---|
| ルーティング | react-routerなど別途必要 | ファイルベースで自動設定 |
| SSR/SSG | 追加設定が必要 | 標準対応 |
| 画像最適化 | 手動対応 | <Image>コンポーネントで自動 |
| フォント最適化 | 手動対応 | next/fontで自動 |
| API Routes | 別サーバーが必要 | 同一プロジェクト内に作成可能 |
プロジェクトの作成
create-next-app を使うと、設定が整った状態でプロジェクトを作成できます。
npx create-next-app@latest my-app
コマンドを実行すると、いくつかの質問が表示されます。初心者には以下の設定がおすすめです。
Would you like to use TypeScript? › Yes
Would you like to use ESLint? › Yes
Would you like to use Tailwind CSS? › Yes
Would you like your code inside a `src/` directory? › Yes
Would you like to use App Router? › Yes
Would you like to use Turbopack for next dev? › Yes
Would you like to customize the import alias? › No
作成後、開発サーバーを起動します。
cd my-app
npm run dev
http://localhost:3000 にアクセスすると、Next.jsのデフォルトページが表示されます。
App Routerのディレクトリ構造
Next.js 13で導入されたApp Routerでは、src/app/ ディレクトリ内のファイル配置がそのままURLになります。
src/
└── app/
├── layout.tsx # ルートレイアウト(全ページ共通)
├── page.tsx # / (トップページ)
├── loading.tsx # ローディング画面
├── not-found.tsx # 404ページ
├── globals.css # グローバルCSS
├── about/
│ └── page.tsx # /about ページ
├── blog/
│ ├── page.tsx # /blog ページ(記事一覧)
│ └── [slug]/
│ └── page.tsx # /blog/記事のスラッグ(動的ルート)
└── api/
└── posts/
└── route.ts # /api/posts(APIエンドポイント)
layout.tsx(ルートレイアウト)
全ページに共通するHTMLの骨格を定義します。ヘッダー・フッターなどを配置する場所です。
// src/app/layout.tsx
import type { Metadata } from 'next';
import { Noto_Sans_JP } from 'next/font/google';
import './globals.css';
const notoSansJP = Noto_Sans_JP({
subsets: ['latin'],
weight: ['400', '700'],
});
export const metadata: Metadata = {
title: 'My Blog',
description: 'Next.jsで作ったブログです',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ja">
<body className={notoSansJP.className}>
<header className="border-b px-4 py-3">
<a href="/" className="text-xl font-bold">My Blog</a>
</header>
<main className="max-w-3xl mx-auto px-4 py-8">
{children}
</main>
<footer className="border-t px-4 py-6 text-center text-sm text-gray-500">
© 2026 My Blog
</footer>
</body>
</html>
);
}
page.tsx(ページコンポーネント)
// src/app/page.tsx
export default function HomePage() {
return (
<div>
<h1 className="text-3xl font-bold mb-4">ようこそ</h1>
<p className="text-gray-600">Next.jsで作ったブログです。</p>
</div>
);
}
ファイルベースルーティング
App Routerでは、app/ 以下のフォルダ名がURLパスになります。
| ファイルパス | URL |
|---|---|
app/page.tsx | / |
app/about/page.tsx | /about |
app/blog/page.tsx | /blog |
app/blog/[slug]/page.tsx | /blog/任意の値 |
app/shop/[...slug]/page.tsx | /shop/a/b/c など |
[slug] のような角括弧で囲まれたフォルダは「動的ルート」と呼ばれ、URLのパラメータとして値を受け取れます。
// src/app/blog/[slug]/page.tsx
type Props = {
params: { slug: string };
};
export default function BlogPost({ params }: Props) {
return (
<article>
<h1>記事スラッグ: {params.slug}</h1>
</article>
);
}
Server ComponentsとClient Componentsの違い
App RouterではデフォルトですべてのコンポーネントがServer Components(サーバーコンポーネント)として動作します。
Server Components(デフォルト):
- サーバー側でHTMLとして生成される
- データベースや外部APIへのアクセスをコンポーネント内で直接行える
useState、useEffectなどのReact Hooksは使えない- JavaScriptがクライアントに送られないのでバンドルサイズが増えない
Client Components:
- ファイルの先頭に
'use client'と記述する - ブラウザ上で動作し、React Hooksが使える
- インタラクティブなUI(クリックイベント、フォーム状態管理など)に使う
// Server Component(データ取得)
// src/app/blog/page.tsx
async function getPosts() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
return res.json();
}
export default async function BlogPage() {
const posts = await getPosts();
return (
<div>
<h1 className="text-2xl font-bold mb-6">記事一覧</h1>
<ul className="space-y-4">
{posts.map((post: { id: number; title: string }) => (
<li key={post.id} className="border rounded-lg p-4">
<a href={`/blog/${post.id}`} className="font-medium hover:text-blue-600">
{post.title}
</a>
</li>
))}
</ul>
</div>
);
}
// Client Component(インタラクティブなUI)
// src/components/LikeButton.tsx
'use client';
import { useState } from 'react';
export default function LikeButton() {
const [count, setCount] = useState(0);
return (
<button
onClick={() => setCount(count + 1)}
className="px-4 py-2 bg-red-50 text-red-600 rounded-full hover:bg-red-100"
>
♥ {count}
</button>
);
}
SSR・SSG・ISRの使い分け
SSR(Server-Side Rendering)
リクエストのたびにサーバーでHTMLを生成します。リアルタイム性が必要なデータに向いています。
// Next.js App Routerでは、fetchのcacheオプションで制御
export default async function Page() {
// cache: 'no-store' でSSR(毎回サーバーで生成)
const data = await fetch('https://api.example.com/data', {
cache: 'no-store',
});
const json = await data.json();
return <div>{json.title}</div>;
}
SSG(Static Site Generation)
ビルド時にHTMLを一度生成して静的ファイルとして配信します。ブログ・ドキュメントサイトに最適です。
// cache: 'force-cache'(デフォルト)でSSG
export default async function Page() {
const data = await fetch('https://api.example.com/data', {
cache: 'force-cache',
});
const json = await data.json();
return <div>{json.title}</div>;
}
ISR(Incremental Static Regeneration)
SSGで生成した静的ファイルを一定時間ごとに再生成します。ブログや商品ページなど、データが時々更新されるコンテンツに向いています。
// next.revalidate でISR(指定秒数後に再生成)
export default async function Page() {
const data = await fetch('https://api.example.com/data', {
next: { revalidate: 3600 }, // 1時間ごとに再生成
});
const json = await data.json();
return <div>{json.title}</div>;
}
Link・Image・Fontコンポーネント
Next.jsには、パフォーマンスを自動的に最適化するコンポーネントが用意されています。
import Link from 'next/link';
import Image from 'next/image';
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
export default function Example() {
return (
<div className={inter.className}>
{/* Linkコンポーネント:クライアントサイドナビゲーション */}
<Link href="/about" className="text-blue-500 hover:underline">
Aboutページへ
</Link>
{/* Imageコンポーネント:自動的にWebP変換・遅延読み込み・サイズ最適化 */}
<Image
src="/images/sample.jpg"
alt="サンプル画像"
width={800}
height={400}
priority // ファーストビューの画像にはpriority属性を付ける
/>
</div>
);
}
実践:シンプルなブログ風ページの作成
以下は、JSONPlaceholderのAPIを使って記事一覧と詳細ページを作る最小構成の例です。
// src/app/blog/page.tsx(記事一覧)
type Post = {
id: number;
title: string;
body: string;
};
export default async function BlogListPage() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=10', {
next: { revalidate: 3600 },
});
const posts: Post[] = await res.json();
return (
<div>
<h1 className="text-3xl font-bold mb-8">ブログ一覧</h1>
<div className="space-y-4">
{posts.map((post) => (
<Link
key={post.id}
href={`/blog/${post.id}`}
className="block border rounded-lg p-4 hover:border-blue-300 hover:bg-blue-50 transition-colors"
>
<h2 className="font-semibold text-gray-900">{post.title}</h2>
<p className="text-sm text-gray-500 mt-1 line-clamp-2">{post.body}</p>
</Link>
))}
</div>
</div>
);
}
// src/app/blog/[id]/page.tsx(記事詳細)
type Props = {
params: { id: string };
};
export default async function BlogDetailPage({ params }: Props) {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`, {
next: { revalidate: 3600 },
});
const post = await res.json();
return (
<article>
<h1 className="text-3xl font-bold mb-4">{post.title}</h1>
<p className="text-gray-700 leading-relaxed">{post.body}</p>
<div className="mt-8">
<Link href="/blog" className="text-blue-500 hover:underline">
← 記事一覧に戻る
</Link>
</div>
</article>
);
}
Next.js超入門
Next.jsの基礎からApp Router、サーバーコンポーネント、データフェッチまでを丁寧に解説した日本語入門書。これからNext.jsを始める方に最適な一冊です。
※ アフィリエイトリンクを含みます
Udemy — Next.js 14 & React - The Complete Guide
Next.js 14のApp Router、Server Actions、認証実装まで網羅した英語ベストセラー講座。ハンズオン形式で実践的なアプリ開発スキルが身につきます。
※ アフィリエイトリンクを含みます
まとめ
Next.jsはファイルベースのルーティング、Server/Client Componentsの使い分け、SSR/SSG/ISRのデータフェッチ戦略など、現代のWeb開発に必要な機能が揃ったフレームワークです。create-next-app でプロジェクトを作成し、app/page.tsx を編集するところから始めましょう。Server Componentsでデータを取得してHTMLを組み立て、インタラクティブな部分にだけ 'use client' を使うというパターンを身につけることが、Next.js習得の第一歩です。