ブログ一覧に戻る
TypeScript開発効率化

Next.js App Router のベストプラクティス 2026年版

はじめに

Next.js の App Router が安定版になってから1年以上が経ち、ベストプラクティスも固まってきました。本記事では、実際のプロダクション運用で得た知見をまとめます。

Server Components と Client Components の使い分け

Server Components を使うべきケース

  • データベースへの直接アクセスが必要な場合
  • 機密情報(APIキーなど)を扱う場合
  • 大きな依存関係を使うが、クライアントバンドルに含めたくない場合

Client Components を使うべきケース

  • useState, useEffect などの React Hook を使う場合
  • ブラウザ API にアクセスする場合
  • イベントハンドラが必要な場合
// Server Component(デフォルト)
async function UserProfile({ userId }: { userId: string }) {
  const user = await db.user.findUnique({ where: { id: userId } });
  return <div>{user.name}</div>;
}

// Client Component
("use client");
function LikeButton() {
  const [liked, setLiked] = useState(false);
  return <button onClick={() => setLiked(!liked)}>♥</button>;
}

データフェッチ戦略

App Router では、コンポーネント単位でデータをフェッチするのが基本方針です。

リクエストの重複排除

React は同一リクエストを自動的に重複排除します。同じデータを複数のコンポーネントで必要とする場合、それぞれのコンポーネントで fetch を呼んでも問題ありません。

Streaming と Suspense

loading.tsx<Suspense> を使うことで、ページの一部を先に表示し、残りを後からストリーミングできます。

import { Suspense } from "react";

export default function Page() {
  return (
    <div>
      <h1>ダッシュボード</h1>
      <Suspense fallback={<Skeleton />}>
        <SlowComponent />
      </Suspense>
    </div>
  );
}

キャッシュ制御

Next.js 15 以降、fetch のデフォルトキャッシュ動作が変更されました。明示的にキャッシュ戦略を指定することを推奨します。

// 静的データ(ビルド時に取得)
fetch(url, { cache: "force-cache" });

// 動的データ(毎回取得)
fetch(url, { cache: "no-store" });

// 時間ベースの再検証
fetch(url, { next: { revalidate: 3600 } });

まとめ

App Router は Server Components を活用することで、パフォーマンスとDXの両方を向上させることができます。まだ使っていない方は、ぜひ試してみてください。