Next.js プロジェクトの標準ディレクトリ構成とは?

執筆 쉬었음.com

標準的な Next.js プロジェクトのディレクトリ構成とは、すべてのチームに同一に適用できる唯一の正しいフォルダツリーを指すものではありません。これは、フレームワークが解釈する必要があるルーティングファイルには定義済みの規約に従い、それ以外のコードはプロジェクトの性質に応じて配置することを意味します。新規プロジェクトでは、通常、URL とページのエントリーポイントの中心を src/app にし、複数箇所で使用する UI を components に分け、必要に応じて機能固有のロジックを features に置き、共有ユーティリティを lib に保持する方法が理解しやすいでしょう。現在の Next.js では App Router が主なルーティング方式であり、Pages Router も引き続きサポートされています。 nextjs.orgnextjs.org

初めて構成を定義するときに重要なのは、できるだけ多くのフォルダを作ることではありません。まず、どのファイルが URL を作るのか、どのファイルがレイアウト、エラー画面、API を処理するのか、どのコードが特定の画面内でのみ使われるのかを区別します。この記事では、これらの区別に基づく、保守しやすい App Router 中心の構成を検討します。

Next.js に「唯一の標準構成」がないのはなぜですか?

Next.js はファイルやフォルダからルートを構築するための規約を提供しますが、すべてのコンポーネントやビジネスロジックをどのフォルダに置くべきかまでは規定しません。特に App Router では、フォルダは URL セグメントを表し、page.tsxroute.ts などの特別なファイルが実際の公開エントリーポイントを作成します。対照的に、ルート内に置かれた通常のファイルは、デフォルトでは外部ルートになりません。 nextjs.org

この特性により、Next.js アプリケーション間でも構成は異なり得ます。小規模なマーケティングサイトでは、app と少数の共有コンポーネントだけで十分な場合があります。一方、ダッシュボード、注文、アカウントといった複数ドメインを持つサービスでは、機能固有のコードと共有コードを分けると、変更の影響範囲を把握しやすくなります。これは Next.js が要求する絶対的なルールではなく、ルーティング規約の上にチームが選択して設けるコード整理の方法です。

したがって、「標準」は次の 2 層で考えると混乱しにくくなります。

カテゴリ性質代表例
Next.js が解釈する規約ファイル名と配置場所が動作に直接影響するapp/page.tsxapp/layout.tsxapp/api/users/route.ts
プロジェクトで定義する規約チームが目的に応じて名前と境界を定義するcomponentsfeatureslibhookstypes

第 1 層を任意に変更すると、ルーティングや特別な UI の動作が変わる可能性があります。第 2 層は、規模やドメインの複雑さに応じて省略または統合できます。たとえば、features のない構成も可能であり、小規模なプロジェクトであらゆるコードを過度に細分化する必要はありません。

新規プロジェクトを App Router 中心に設計すべきなのはなぜですか?

App Router は、app ディレクトリに基づいてページとレイアウトを構築するアプローチです。公式ドキュメントは、最新の React 機能を活用するために Pages Router から App Router への移行を推奨していますが、Pages Router 自体もサポートされています。したがって、既存プロジェクトの構成を保守・学習するときは pages の規約を理解すべきですが、新しい構成を設計する際には App Router をデフォルト候補として扱うのが自然です。 nextjs.org

App Router で重要なのは、URL 階層をファイル階層に結び付けることです。たとえば、app/dashboard/page.tsx/dashboard ページのエントリーポイントになり、その配下の app/dashboard/layout.tsx はダッシュボードのサブルートに適用されるレイアウトを提供できます。ルートの app/layout.tsx は、すべてのルートをラップするルートレイアウトです。 nextjs.org

このアプローチは、画面レベルのコードを近くに保つことに適しています。/dashboard でのみ必要なタブ、テーブル、フィルター UI は app/dashboard 配下に置けます。一方、複数の画面で再利用するボタンや入力フィールドは外部の共有フォルダに移せます。重要な判断基準は「このファイルをどの技術で書いたか」ではなく、「どの範囲で再利用されるか」です。

ただし、App Router を使用することは、すべてのコードを app 内に置かなければならないことを意味しません。app を URL と特別なファイルを読み取りやすくする境界として扱い、必要に応じて共有コードや複雑な機能実装を別フォルダに分けられます。この分離は Next.js が自動で行うものではなく、チームが一貫して定義する構造上の規約です。

src フォルダを使うのはいつで、ルートには何を置きますか?

src は任意です。使用すると、app とアプリケーションのソースコードを src 配下にまとめ、設定ファイルと実行時のコードを視覚的に分離できます。一方、publicpackage.jsonnext.config.jstsconfig.json.env.* ファイルはプロジェクトルートに置きます。 nextjs.org

以下は、App Router と src を併用する場合の理解しやすい例です。

my-app/
├─ public/
│  ├─ images/
│  └─ fonts/
├─ src/
│  ├─ app/
│  │  ├─ layout.tsx
│  │  ├─ page.tsx
│  │  ├─ globals.css
│  │  ├─ (marketing)/
│  │  │  └─ about/
│  │  │     └─ page.tsx
│  │  ├─ dashboard/
│  │  │  ├─ layout.tsx
│  │  │  ├─ page.tsx
│  │  │  ├─ loading.tsx
│  │  │  ├─ error.tsx
│  │  │  └─ _components/
│  │  └─ api/
│  │     └─ users/
│  │        └─ route.ts
│  ├─ components/
│  ├─ features/
│  ├─ lib/
│  ├─ hooks/
│  └─ types/
├─ .env.local
├─ next.config.js
├─ package.json
└─ tsconfig.json

この例で src はアプリケーションコードの境界にすぎず、動作を変える必須の仕組みではありません。既存プロジェクトにすでにルートの app がある場合、無理に src を追加するより、確立済みの規約に一貫して従うほうがよいことがあります。特に、ルートと src の両方に app または pages というディレクトリがある場合はルートディレクトリが優先されるため、移行中に重複した構成を長期間残さないことが重要です。 nextjs.org

src を選ぶ実務的な基準は単純です。設定ファイルとプロダクトコードを明確に分けたい場合や、ソースファイル数の増加が予想される場合に役立ちます。反対に、学習用プロジェクトや、すでにルート構成が明快な非常に小規模なプロジェクトで採用する必要はありません。

app フォルダ内のどのファイルが実際のルートを作成しますか?

App Router では、フォルダは URL の一部、すなわちセグメントを表します。しかし、app/dashboard フォルダを作成するだけでは /dashboard は公開ページになりません。そのフォルダに page.tsx があればページ UI を提供するルートになり、route.ts があれば Route Handler に基づく API エンドポイントになります。 nextjs.org

たとえば、次の構成を考えてみましょう。

src/app/
├─ page.tsx
├─ about/
│  └─ page.tsx
├─ dashboard/
│  ├─ page.tsx
│  └─ reports/
│     └─ page.tsx
└─ api/
   └─ users/
      └─ route.ts

この場合、page.tsx はそれぞれ //about/dashboard/dashboard/reports に対応します。api/users/route.ts は UI ページではなく、API エンドポイントを定義します。page.tsxroute.ts がルートの公開エントリーポイントであると理解すると、ほかのファイルを同じフォルダに置ける理由が明確になります。 nextjs.org

この性質は コロケーション として捉えられます。コロケーションとは、関連するコードを近くに置く整理方法です。たとえば、dashboard 内でしか使わないテーブルコンポーネント、画面固有の整形関数、テストデータ変換コードは、app/dashboard の近くに置けます。これは共有フォルダを使ってはいけないという意味ではありません。他のルートでも再利用されるコードだけを、より広いスコープのフォルダに移せばよいのです。

layout、loading、error ファイルはどのように分けるべきですか?

layout.tsx は共有 UI シェルを担当します。ルートの app/layout.tsx はすべてのルートをラップし、子フォルダの layout.tsx はサブルートにネストして適用されます。たとえば、ダッシュボードのナビゲーションを /dashboard/dashboard/reports で共有する場合、app/dashboard/layout.tsx に置けます。 nextjs.org

page.tsx は特定のパスで表示されるページ UI です。レイアウトが繰り返される外側の構造であるなら、ページはその中で変化するパス固有のコンテンツに近いものです。これらを分けることで、共有ナビゲーションやフレームを各ページに繰り返す必要がなくなります。

App Router には、状態固有の UI 用予約ファイルもあります。loading.tsx はローディング UI、error.tsx はエラー UI、not-found.tsx は Not Found UI に使用します。通常のコンポーネントファイルとは異なり、Next.js はこれらのファイルを特定の役割として解釈するため、役割とスコープを意識して配置すべきです。 nextjs.org

たとえば、/dashboard 配下でデータの準備中に別画面を表示したい場合は app/dashboard/loading.tsx を、同じ範囲でエラー処理用の画面が必要な場合は app/dashboard/error.tsx を検討できます。これらのファイルをすべてのフォルダに機械的に追加する必要はありません。各ルートに個別の待機、エラー、Not Found 状態の UI が本当に必要かどうかで判断すると、構成を簡潔に保てます。

動的ルートと API ルートはフォルダ名でどのように表しますか?

ルートの一部があらかじめ決まっていない場合は、角括弧記法を使用します。[slug] は 1 つの動的セグメント、[...slug] は後続するすべてのサブセグメント、[[...slug]] はそのサブセグメントがなくてもよい省略可能な形式を意味します。 nextjs.org

たとえば、投稿 ID が変化するページは次のように構成できます。

src/app/posts/
└─ [slug]/
   └─ page.tsx

この構成で [slug] は固定のフォルダ名ではなく、URL の変化する部分を受け取るプレースホルダーです。一方、複数階層のルートを 1 つの規約で処理する必要がある場合は、[...slug] または [[...slug]] を検討します。どの記法を選ぶかは、少なくとも 1 つのサブパスが必須かどうか、パスなしの場合も同じ画面で処理すべきかどうかによって決まります。 nextjs.org

API を構築する場合、route.ts は Route Handler のエントリーポイントです。そのため、app/api/users/route.ts のようなフォルダで URL 構造を表し、末尾に route.ts を置けます。ページと API のどちらでも、フォルダ階層を読むことでおおよそのパスを推測できます。ただし、UI とサーバー側処理のコードが同じ領域で過度に混在して長大にならないよう、専用の実装ファイルは適切に分けるほうがよいでしょう。 nextjs.org

ルートグループとプライベートフォルダが必要なのはなぜですか?

(marketing) のように括弧で囲んだフォルダは、ルートグループです。URL には含まれない論理的なグループ化です。たとえば、会社情報や料金などのマーケティング向けページをまとめつつ、プロダクト利用画面は別構成で管理できます。app/(marketing)/about/page.tsx はグループ名を含まない /about ルートになります。 nextjs.org

ルートグループは、URL を変えずにレイアウトの境界やコードの所有範囲を示したい場合に便利です。ただし、グループ名は URL に現れないため、別々のグループが最終的に同じ URL を作成すると競合します。また、複数のルートレイアウト間を移動する構成ではフルページロードが発生する場合があるため、フォルダをきれいに見せる目的だけでルートレイアウトを分割すべきではありません。 nextjs.org

_components_lib のようにアンダースコアで始まるフォルダはプライベートフォルダであり、ルーティングから除外されます。App Router では通常ファイルはデフォルトでルートにならないため、アンダースコアは厳密には必須ではありません。それでも、ルーティング用の特別なファイルと内部実装の境界を視覚的に示したい場合や、予約ファイル名との混同を避けたい場合に役立ちます。 nextjs.org

たとえば、app/dashboard/_components/summary-card.tsx は、ダッシュボード固有の UI であることを伝えます。ただし、そのコンポーネントが他の機能でも繰り返し使われるようになった場合は、アンダースコアフォルダから共有の components または適切な機能境界へ移すことを検討するほうが自然です。フォルダ接頭辞はアクセス制御の仕組みではなく、コードの役割を伝える表記であることを覚えておいてください。

components、features、lib、hooks、types はどのように区別すべきですか?

これらのフォルダは、予約済みの App Router 規約ではなく、任意の整理上の選択です。そのため、名前自体よりもチームで合意した責務の境界が重要です。次の区別は一般的な出発点です。

フォルダ通常置くコード配置の判断基準
components複数画面で再利用する UI特定の URL やドメインに結び付いていないか?
features機能またはドメインレベルの実装アカウント、注文、ダッシュボードのような明確なビジネス概念があるか?
lib共有ユーティリティとクライアントUI ではなく共有ツールか?
hooks再利用可能なフック複数コンポーネントで同じ状態や振る舞いを共有するか?
types共有型複数領域が同じ型定義を参照するか?

components には汎用ボタンだけでなく、複数の機能間で共有する複合 UI も含められます。ただし、最初からすべての UI 要素をグローバルな共有コンポーネントにすると、実際には 1 つの画面でしか必要ない実装まで抽象化してしまうことがあります。まずルートの近くに置き、2 箇所以上で安定して使われ、明確な共有インターフェースを持つようになってから移動する方法もあります。

features は、ドメイン中心の構成が必要な場合に特に読みやすくなります。たとえば、注文とアカウントがそれぞれ独立した画面、UI、データ処理コードを持つ場合、features/ordersfeatures/account のようにグループ化できます。反対に、単純なサイトに機能フォルダを作りすぎると、ファイルを探すだけで多くのフォルダを移動することになります。機能の境界が実際のプロダクト概念と一致する場合にのみ導入するほうがよいでしょう。

lib は、共有ユーティリティやサーバークライアントなど、UI 以外の基盤コードの配置候補です。ただし、すべての関数ファイルを lib に蓄積すると、大きく理解しにくい保管場所になりかねません。実践的なルールとして、1 つの機能でしか使わないツールはその機能またはルートの近くに保ち、複数箇所で共有するコードだけを lib に移します。

public と環境変数ファイルをプロジェクトルートに置くのはなぜですか?

public は静的ファイル用のプロジェクトルートフォルダです。そこに置いたファイルはルートパスから配信されます。たとえば、public/profile.png/profile.png として参照します。これにより、画像やフォントなど静的に配信されるファイルを 1 か所に置けます。 nextjs.org

src を使用する場合でも、publicsrc/public に移す構成と考えるべきではありません。public はプロジェクトルートに残り、package.jsonnext.config.jstsconfig.json.env.* もルートから管理します。特に、.env.local のようなローカル環境変数ファイルにはシークレットが含まれる可能性があるため、バージョン管理に含めない運用ルールを定めることが重要です。 nextjs.org

静的アセットとアプリケーションソースの役割を分けると、パスを解釈しやすくなります。src/app 内のファイルは画面やルーティングを構築するコードであり、public 内のファイルは URL で参照する静的アセットです。同じ画像を画面で使用する場合でも、どこに置くかによって配信方法と参照パスを異なるものとして理解する必要があります。

Pages Router の構成とはどのように異なりますか?

Pages Router は、pages ディレクトリ内のファイルをルートとして扱います。たとえば、pages/index.tsx/ に、pages/about.tsx/about に対応します。予約ファイルの規約では、_app_document404500 などにも特別な役割が割り当てられます。 nextjs.org

App Router と Pages Router をフォルダ名だけが異なるアプローチと考えると、誤りを起こしやすくなります。App Router では、フォルダセグメント配下の page.tsxlayout.tsxroute.ts といった特別なファイルが責務を分担し、通常ファイルはデフォルトではルートになりません。Pages Router では、pages 内のファイルがより直接的にルートと結び付きます。 nextjs.orgnextjs.org

既存の Pages Router プロジェクトを扱う場合は、現在の pages ベースの規約を尊重すべきです。反対に、新規プロジェクトを始める場合は、App Router 中心の例を基にし、本当に必要になったときにだけ整理用フォルダを追加するとオーバーヘッドを減らせます。同じディレクトリ設計の中で、2 つのルーターの規約を混同しないことが重要です。

実際のプロジェクトで構成を選ぶにはどのような基準を使うべきですか?

まず、URL 構造から始めます。ユーザーがアクセスする主要なパスを列挙し、各パスで使用する共有レイアウトを決めます。その結果を、app 内のフォルダと page.tsxlayout.tsx の配置で表現します。URL を変えずに画面領域やレイアウトを分ける明確な理由がある場合は、ルートグループを使用します。 nextjs.orgnextjs.org

次に、再利用のスコープを評価します。1 つのルートでしか使わないコードはそのルートの近くに置きます。複数のルートで使う UI は components のような広いスコープに移し、複数の機能で使うユーティリティは lib に移せます。最初からすべてを汎用化するのではなく、実際の再利用や変更のパターンが現れたときにコードを分けると、不要な抽象化を減らせます。

3 つ目は、機能の独立性を考えることです。アカウント、管理、注文のように、責務領域と用語が明確な機能が大きくなる場合は、features のようなドメイン境界が役立ちます。一方、画面数が少なく、機能間の区別が弱い場合は、app 内のコロケーションと少数の共有フォルダで十分なことがあります。

4 つ目は、チームの探索コストを確認することです。新しいチームメンバーが特定 URL のコードを探すとき、app のパスをたどってページと専用実装を見つけられるべきです。共有ボタンやユーティリティの名前と場所も予測可能であるべきです。良い構成は、流行しているフォルダ名よりも、この予測可能性から生まれます。

避けるべき誤解と構造上の落とし穴は何ですか?

最初の誤解は、「フォルダを作ればすぐ URL が作られる」というものです。App Router ではフォルダはセグメントを表しますが、公開ページまたは API エンドポイントにするには page.tsx または route.ts が必要です。このルールにより、関連する内部ファイルをルートフォルダ内にまとめて置けます。 nextjs.org

2 つ目の誤解は、「アンダースコアフォルダがなければ内部ファイルはすべて公開される」というものです。App Router の通常ファイルはデフォルトではルートになりません。_components のような名前は必須のセキュリティ機能ではなく、内部実装を示し、そのフォルダをルーティングから除外する整理ツールです。 nextjs.org

3 つ目の誤解は、「ルートグループ名も URL に含まれる」というものです。(marketing) の括弧付きの名前は URL から除外されます。この便利さがあるため、異なるグループが同じ最終 URL を作らないよう確認すべきです。複数のルートレイアウトに分割する場合、グループ間のナビゲーション時にフルページロードが発生する可能性も、構成を設計する前に考慮すべき点です。 nextjs.org

最後に、src を導入する際に、同じ app または pages ディレクトリをルートと src の両方に残す誤りを避けてください。この場合はルートが優先されるため、期待したソースが実行されていないように見えることがあります。構造の変更は、一度にフォルダを追加するだけの作業ではありません。実際にどのディレクトリがルーティングの基盤として機能しているかを確認しながら進めてください。 nextjs.org

結論:標準とはフォルダ一覧ではなく役割の境界です

Next.js プロジェクト構成の出発点は、app と特別なファイルによって定義されるルーティング規約です。新しい App Router プロジェクトでは、URL、ページ、レイアウトの中心を src/app に置き、public はルートの静的アセットフォルダとして維持し、コード再利用の実際のスコープとドメインの複雑さに応じて componentsfeatureslibhookstypes を選択できます。 nextjs.orgnextjs.org

最終的に、良い構成とはフォルダ数が最も多いものではありません。チームメンバーが特定ルートの画面、その画面専用のコード、複数箇所で共有するコードの場所を容易に予測できる構成です。Next.js のファイル規約には正確に従い、その上にある整理方法は、プロジェクトの成長速度と変更パターンに合わせて段階的に調整してください。

よくある質問

Next.js では src フォルダを使う必要がありますか?

いいえ。src は任意です。使用する場合は app とアプリケーションコードを src 配下に置けますが、public、主要な設定ファイル、環境変数ファイルはプロジェクトルートに置きます。ルートと src の両方に同名の app または pages ディレクトリがある場合は、ルートディレクトリが優先されます。

app フォルダ内に作成したすべてのフォルダは URL になりますか?

いいえ。フォルダは URL セグメントを表しますが、公開ページまたは API エンドポイントにするには、そのセグメントに page.tsx または route.ts が必要です。このため、ルート固有のコンポーネントやユーティリティをルートフォルダ内に置けます。

(marketing) のような括弧付きフォルダは URL に含まれますか?

いいえ。括弧付きの名前はルートグループであり、URL を変更せずにルートを論理的に整理したり、個別のレイアウトを適用したりするためのものです。ただし、異なるグループが同じ URL を生成すると競合が発生します。

新しい Next.js プロジェクトでは App Router と Pages Router のどちらを使うべきですか?

Pages Router は引き続きサポートされていますが、公式ドキュメントは最新の React 機能を利用するために App Router への移行を推奨しています。既存構造に由来する特別な制約がない限り、新規プロジェクトでは App Router をデフォルト候補として検討できます。既存の Pages Router プロジェクトでは、現在のルーティング規約に従うか、必要に応じて移行を評価できます。

public フォルダ内のファイルはどのように参照しますか?

public はプロジェクトルートにある静的ファイル用フォルダです。たとえば、public/profile.png に置いたファイルは /profile.png として参照します。