ひとことで言うと#
フロントエンド・バックエンド・共有ライブラリなど複数のプロジェクトを単一のリポジトリ(モノレポ)で管理する戦略。コードの共有・一貫性・アトミックな変更が容易になる一方、ビルド時間やアクセス制御に工夫が要る。Google、Meta、Microsoftなど大規模組織で採用されてきた手法である。
押さえておきたい用語#
- モノレポ(Monorepo)
- 複数のプロジェクトやパッケージを1つのリポジトリに格納する管理方式。monolithic repository の略。
- ポリレポ(Polyrepo)
- プロジェクトごとに個別のリポジトリを持つ従来型の管理方式。マイクロサービスと親和性が高いとされるが、横断的変更のコストが高い。
- アトミックコミット(Atomic Commit)
- 複数パッケージにまたがる変更を1つのコミットで同時に反映できること。モノレポの最大の利点のひとつ。
- ビルドキャッシュ(Build Cache)
- 変更がないパッケージのビルド結果を再利用する仕組み。Turborepo、Nx、Bazelなどが提供する。
- コードオーナーシップ(Code Ownership / CODEOWNERS)
- モノレポ内のディレクトリやファイルごとにレビュー責任者を定義する仕組み。GitHubのCODEOWNERSファイルで管理されることが多い。
モノレポ戦略の全体像#
こんな悩みに効く#
- 共有ライブラリの変更を各リポジトリに反映するのに毎回PRを5つ出している
- APIの型定義がフロントとバックで二重管理になっており、不整合が頻発する
- チーム間でコーディング規約やlint設定がバラバラで、レビューの基準が揃わない
- リポジトリが30個以上に分かれ、全体の依存関係を誰も把握できていない
基本の使い方#
現在のポリレポ構成で、どのリポジトリがどのリポジトリに依存しているかを図にする。
- パッケージマネージャの依存定義(package.json、go.mod等)を元に依存グラフを作る
- 「変更するとき他のリポジトリも同時に変更が必要」なペアを洗い出す
- 依存が密結合しているグループがモノレポ化の最有力候補になる
チームの規模・言語・ビルド複雑度に合わせてビルドツールを選ぶ。
- Turborepo: JavaScript/TypeScript中心、セットアップが簡単、リモートキャッシュ対応
- Nx: プラグインが豊富、影響範囲の自動検出、大規模チーム向け
- Bazel: 多言語対応、超大規模向け、学習コストは高い
- pnpm workspaces: 軽量、パッケージ管理に特化、小〜中規模向け
全リポジトリを一気に統合するのではなく、共有パッケージから順に移行する。
- まず共有ライブラリ(型定義、ユーティリティ、UIコンポーネント)をモノレポに移す
- 次にアプリケーション(フロントエンド、バックエンド)を順次統合する
- CIパイプラインは移行と並行して構築し、影響を受けたパッケージだけビルド・テストする設定にする
モノレポが大きくなっても秩序を保つためにガバナンスを設定する。
- CODEOWNERSファイルでディレクトリごとのレビュー責任者を定義する
- パッケージ間の依存方向ルール(例: appsはpackagesに依存してよいが逆は不可)を設ける
- CIでビルドキャッシュのヒット率を計測し、定期的にチューニングする
具体例#
従業員60名のSaaS企業。フロントエンドチーム8名が、管理画面・ユーザー画面・LP・共有UIライブラリ・設定パッケージの5リポジトリを運用していた。
課題:
- 共有UIライブラリを更新するたびに、他の4リポジトリにそれぞれPRを出す必要があった(月平均20件の横断PR)
- npm publishの手順でミスが多く、バージョン不整合で月に2〜3回ビルドが壊れた
- ESLintとTSConfigの設定が各リポジトリで微妙に異なり、コードレビューで揉めていた
移行: Turborepoを採用し、2か月かけて段階移行。まず共有UIライブラリとconfig、次にアプリケーション3つを統合。
結果:
- 横断PRが月20件 → 0件に(アトミックコミットで同時変更)
- ビルド破損: 月2〜3回 → 月0.2回(四半期に1回程度)
- CIの平均実行時間: Turborepoのキャッシュにより12分 → 3分
- lint設定を一元化したことで、コードレビューの「スタイル指摘」が70%減
120名規模のフィンテック企業。バックエンドはGoで書かれた8つのマイクロサービス、フロントエンドはTypeScript(Next.js)で構成されていた。各サービスのリポジトリは独立しており、API型定義はOpenAPIスキーマから各リポジトリで個別にコード生成していた。
課題:
- スキーマ変更後にフロントのコード生成が漏れ、本番でAPI不整合が発生(四半期に3〜4件)
- サービス間のgRPC型定義も各リポジトリに散在し、protobufの同期に毎回半日かかっていた
移行:
Nxを採用し、OpenAPIスキーマとprotobuf定義をpackages/schemasに集約。各サービスは同じリポジトリ内から型を参照する構成に変更。
結果:
- API型の不整合による本番インシデント: 四半期3〜4件 → 0件
- スキーマ変更の反映漏れ: CIが影響範囲の全サービスを自動テストするため検出率100%
- protobuf同期の工数: 半日 → 不要(同一リポジトリ内で直接参照)
- 新サービスの立ち上げ: テンプレートジェネレータにより2日 → 2時間
創業1年目、エンジニア6名のスタートアップ。Webアプリ(Next.js)、管理画面(Next.js)、バックエンドAPI(Node.js)、バッチ処理(Node.js)の4つのアプリケーションを開発していた。
創業当初はポリレポで始めたが、3か月目で共有コードのコピペが蓄積し、「同じバリデーションロジックが4か所にある」状態になった。
移行: pnpm workspacesとTurborepoで構成。半日でモノレポに統合(まだコードベースが小さかったため)。
構成:
apps/web ... ユーザー向けWebアプリ
apps/admin ... 管理画面
apps/api ... バックエンドAPI
apps/batch ... バッチ処理
packages/db ... Prismaスキーマ・マイグレーション
packages/auth ... 認証ロジック
packages/types ... 共有型定義
packages/config ... ESLint・TSConfig結果(移行6か月後):
- 共有コードの重複: 4か所 → 1か所(packages/に集約)
- Prismaスキーマ変更時の反映漏れ: 月2〜3回 → 0回
- 新機能の開発速度: エンジニアの主観で「体感1.5倍」(横断的な変更が1PRで済むため)
- オンボーディング: 新メンバーが
git clone1回で全環境を手元に構築でき、初日からPRを出せた
やりがちな失敗パターン#
- ビルドキャッシュを設定せずに統合する — リポジトリが大きくなるとCIが全パッケージをビルドし、実行時間が爆発する。Turborepo/Nxのリモートキャッシュは初日から設定すべき
- 全リポジトリを一気に統合しようとする — 大規模な移行は必ず問題が出る。共有パッケージから段階的に移し、各段階でCIが安定してから次に進む
- パッケージ間の依存方向を管理しない — 何でも自由にimportできる状態は「分散モノリス」になる。パッケージの依存方向ルールをlintで強制する
- CODEOWNERSを設定しない — モノレポでは全員が全ファイルにPRを出せるため、レビューが誰にも割り当てられず放置されるリスクがある
まとめ#
モノレポ戦略は、複数プロジェクトを単一リポジトリで管理することで、アトミックコミット・コード共有・一貫した設定のメリットを得るアプローチである。一方でビルド時間の肥大化やアクセス制御の複雑さという課題があり、ビルドキャッシュとCODEOWNERSで対処する必要がある。大事なのはモノレポを「銀の弾丸」と見なさず、チームの規模と依存関係の密度から判断すること。共有コードが多くチーム間の変更が頻繁なら効果は大きく、独立性の高いサービスならポリレポのままでも問題ない。