🧐

Next.js App Router 私の私による私のためのディレクトリ構成を考える

2025/02/17に公開

はじめに

Next.js App Routerは、いまだWeb上にディレクトリ構成についての情報が少ないように思っているし、私はディレクトリ構成をうまくできていない。
それぞれのプロジェクトや個人開発においてオレオレアーキテクチャ、オレオレディレクトリ構成を利用していると信じてやまない。(実際のところは不明ですが)

これが、私の考えた!! Next.js App Router ディレクトリ構成だ!! 勝負しようぜ!!
(//FIXME 何を? 誰と? 私のと書いてあるけれど、他の人の記事を参考にしまくっていますよね?)

上記は冗談として、誰とも勝負するつもりはありませんので。これは私のためのディレクトリ構成です。

主な採用技術

・Next.js 14 App Router
・TypeScript
・Tailwind CSS
・Zod
・Zustand
・Prisma
・Playwright

ディレクトリ構成

全体像

├─public //静的ファイルを格納するディレクトリ
└─src
   ├─app //ルーティングを担うディレクトリ
   │  ├─layout.tsx
   │  ├─page.tsx //container.tsxを呼び出すだけのコンポーネントとする
   │  ├─container.tsx //データ取得を担うコンポーネント presentational.tsxを呼び出す
   │  ├─presentational.tsx //UI描画を担うコンポーネント
   │  ├─author
   │  │  ├─page.tsx
   │  │  ├─container.tsx
   │  │  └─presentational.tsx
   │  └─posts
   │     └─[postId]
   │        ├─page.tsx
   │        ├─container.tsx
   │        └─presentational.tsx
   │
   ├─features //各機能ごとでのみ利用されるコードを格納するディレクトリ
   │  ├─author
   │  │  ├─components
   │  │  │  └─NameCard.tsx //presentational.tsxから呼び出されるコンポーネント
   │  │  ├─types //型定義+Zodスキーマを格納するディレクトリ
   │  │  ├─tests //単体・結合テストを格納するディレクトリ
   │  │  ├─stores //グローバル状態管理定義を格納するディレクトリ
   │  │  ├─hooks //React Hooksを利用しているロジックを格納するディレクトリ
   │  │  ├─utils //React Hooksを利用していないロジックを格納するディレクトリ
   │  │  ├─services //ビジネスロジックを格納するディレクトリ
   │  │  └─repositories //DB操作を格納するディレクトリ
   │  │
   │  └─posts
   │     ├─components
   │     ├─types
   │     ├─tests
   │     ├─stores
   │     ├─hooks
   │     ├─utils
   │     ├─services
   │     └─repositories
   │
   └─shared //共通コードを格納するディレクトリ
      ├─components //ロジックのない共通コンポーネントを格納するディレクトリ
      ├─i18n //多言語機能を格納するディレクトリ
      ├─googleAnalytics //GA機能を格納するディレクトリ
      ├─types //共通型定義+共通Zodスキーマを格納するディレクトリ
      ├─tests //E2Eテストを格納するディレクトリ
      ├─constants //定数定義を格納するディレクトリ
      ├─libs //ライブラリ固有のコードを格納するディレクトリ
      ├─hooks //React Hooksを利用している共通ロジックを格納するディレクトリ
      ├─utils //React Hooksを利用していない共通ロジックを格納するディレクトリ
      ├─services //共通のビジネスロジックを格納するディレクトリ
      ├─repositories //共通のDB操作を格納するディレクトリ
      └─prisma //Prismaのスキーマ定義を格納するディレクトリ

解説・考慮事項

フロントエンド視点

修正の影響範囲を把握しやすくするため、featuresディレクトリによるコロケーション配置をとることにした。appディレクトリにてRoute Groupsを利用してコロケーション配置をとる方法もあったが、ルーティングを担うものとして可読性を意識し独立させることにした。
データ取得とUI描画を分割したい、かつReact Server Componentsの恩恵を受けたいので、Container/Presentationalパターンをとることにした。

バックエンド視点

リポジトリパターンをまるごと取り込むとPrisma単体を扱う分には過多と考えたが、処理の隠匿、関心の分離をより厳密にやってみたく、Repository層は導入することにした。
Next.jsから外部バックエンドAPIを呼び出すのみであれば、Repository層は不要ではないかと思う。

「View」=presentational.tsxコンポーネント
「Controller」=container.tsxコンポーネント(Server Actions自体)
「Service」=services
「Repository」=repositories
「Model」=PrismaのDBスキーマ定義

終わりに

デコロケーションになっているディレクトリ構成に比べればだいぶスッキリしたし、影響範囲がわかりやすいはずだ。
ディレクトリ構成について、なんとか私がやっていけるだけの道筋が見えたように思う。
ともすると過多な部分もあるので、もっと切り詰めても良いはず。
Container/Presentationalパターンは偉大。そして、多くの先人達の記事もまた偉大。ありがとうございます。

参考文献

https://zenn.dev/akfm/books/nextjs-basic-principle/viewer/part_2_container_1st_design
https://zenn.dev/rio_dev/articles/f7d700690de8da
https://zenn.dev/mybest_dev/articles/c0570e67978673
https://zenn.dev/miumi/articles/562642bf3e15d1
https://zenn.dev/yodaka/articles/eca2d4bf552aeb
https://zenn.dev/michiharu/articles/c2794ddbfec05b
https://zenn.dev/motonosuke/articles/8f4ba3714f30fe
https://zenn.dev/overflow_offers/articles/20231215-directory-structure
https://zenn.dev/cybozu_frontend/articles/design-patterns-in-react
https://zenn.dev/mongolyy/articles/01f0a4375edb2e
https://zenn.dev/naoki_oshiumi/articles/0467a0ecf4d56a
https://zenn.dev/takepepe/articles/nextjs-service-layer
https://zenn.dev/buyselltech/articles/9460c75b7cd8d1
https://zenn.dev/kiwichan101kg/articles/b44305e3049bac
https://zenn.dev/ficilcom/articles/clean_architecture_for_frontend
https://zenn.dev/akfm/articles/7dca8c8543ffe6

Discussion