Nxモノレポ入門:affectedで変更箇所だけ速く回す設計
Nxのタスクキャッシュ・依存グラフ・nx affectedで、巨大リポジトリのCIを変更箇所だけに絞る方法。Claude Codeとの相性も含めコピペで動く手順で解説。
apps/web のボタンの色を変えただけなのに、CIが12分待たせてきました。
中身を見たら、管理画面のテストも、APIのビルドも、関係ないライブラリのlintも、全部走っていた。色を1つ変えただけで、です。僕はその待ち時間に3回コーヒーを淹れ、4回目で「これはおかしい」と気づきました。
問題は「全部入れたこと」じゃなくて、「全部を毎回回していること」でした。リポジトリにアプリやライブラリを詰め込むのはいい。でも、変更と関係ないものまで毎回チェックするのは、ただの無駄です。
これを機械的に解決するのが Nx です。今日は「モノレポってそもそも何が嬉しいの」から、Nxの心臓部である nx affected(変更の影響範囲だけ動かす仕組み)まで、コピペで動く形で書きます。
この記事の要点
- モノレポは「型・UI・設定を1つのPRで直せる」のが最大の利点。欠点はCIが重くなること。
- Nxは依存グラフ(どの部品がどれに依存しているか)を自動で読み取り、
nx affectedで変更の影響範囲だけビルド/テストする。 - タスクキャッシュが効くと、入力が同じビルドは2回目以降スキップされ、結果だけ一瞬で返る。
apps/*(起動・デプロイする単位)とlibs/*(再利用する部品)を分け、libsからappsへは依存させないのが設計の肝。- Claude Codeに大きなリポジトリを触らせるとき、先に
nx graphで境界を見せ、後にnx affectedで検証させると、レビューできる小さな変更に収まる。
モノレポの利点と、正直しんどい欠点
モノレポは、複数のアプリやライブラリを1つのGitリポジトリにまとめる置き方です。逆に、リポジトリを機能ごとに分ける置き方をマルチレポと呼びます。
何が嬉しいのか。一番大きいのは「またぐ変更が1つのPRで終わる」ことです。
たとえばAPIのレスポンス型を変えたとします。マルチレポだと、API側のリポジトリを直してリリース、フロント側のリポジトリで新バージョンを取り込んで直して、またリリース……と往復が発生します。型がズレている期間ができて、その隙にバグが入る。モノレポなら、APIの型もフロントの呼び出しも同じPRで同時に直せます。型がズレる瞬間が存在しません。
| モノレポ | マルチレポ | |
|---|---|---|
| 横断する変更 | 1つのPRで完結 | リポジトリをまたいで往復 |
| コード共有 | importするだけ | publishして取り込む |
| CIの重さ | 油断すると全部走って重い | リポジトリ単位で軽い |
| 境界の崩れやすさ | 何でもimportできて崩れがち | 物理的に分かれて崩れにくい |
正直な欠点も書きます。油断するとCIが地獄になる。冒頭の12分がまさにこれです。それと、importが自由すぎて、本来分けるべき部品どうしがベタベタにくっつく。「便利だから」と何でも共有して、半年後に誰も解けない依存の塊ができあがる。これはあるあるです。
Nxは、この2つの欠点を機械的に潰すための道具です。CIの重さは affected とキャッシュで、境界の崩れは依存グラフの可視化と制約ルールで止めます。
Nxは「賢いビルドツール」ではなく依存グラフを読む道具
Nxを「速いビルドツール」だと思うと、たぶん本質を外します。Nxの正体は、リポジトリ全体の依存関係を読み取って地図を作る道具です。
公式のNx mental modelでは、Nxを5つの概念で説明しています。初心者向けに言い換えると、こうです。
- Project Graph(プロジェクトグラフ):どのプロジェクトがどれに依存しているかの地図。
package.jsonとproject.jsonを読んで、Nxが勝手に作る。 - Task Graph(タスクグラフ):「webをビルドするには先にuiをビルドする必要がある」みたいな、タスクの順番の地図。
- affected(影響範囲):Git差分とグラフを照らし合わせ、変更に巻き込まれるプロジェクトだけを割り出す。
- キャッシュ(computation caching):入力(ソース・設定・依存)が同じタスクは、結果を保存しておいて2回目以降は再実行しない。
- 分散実行:タスクを複数マシンに散らして並列で回す(チーム・大規模向け)。
この記事で覚えてほしいのは、真ん中の2つ、affected と キャッシュだけです。この2つが、冒頭の「色を変えただけで12分」を「色を変えたら数十秒」に変えます。
仕組みはシンプルです。Nxはタスクを実行する前に、入力の中身からハッシュ(指紋のようなもの)を計算します。前回と指紋が同じなら、「中身が1ミリも変わってない」と分かるので、実行せずに保存済みの結果を返す。affected は「変更の指紋が波及するプロジェクト」だけをグラフから選ぶ。だから関係ないものは最初から動かさない。
完成形:アプリとライブラリを5つに分ける
今回は、Reactの顧客画面・管理画面・Node API・共有UI・API契約の5プロジェクトで考えます。最初から巨大な libs/shared を作らないのが大事です。
apps/web → React + Vite(顧客向け画面)
apps/admin → React + Vite(管理画面)
apps/api → Node API
libs/ui → 見た目だけのUI部品
libs/contracts → APIの型とZod schema
libs/config → ESLint / Vitest / TypeScript設定
依存の向きはこうです。apps/* は libs/* を使ってよい。でも libs/* から apps/* へは絶対に依存させない。UIライブラリが apps/web のルーティングや環境変数を読んだ瞬間、それはもう「再利用できる部品」ではなくなるからです。
ここで apps/* は起動・デプロイする単位、libs/* は再利用する部品、と頭の中で線を引いておいてください。libs/ui にAPI通信を書かない。libs/contracts にReactコンポーネントを書かない。役割を1つに絞るほど、後から壊れにくくなります。
セットアップ:コピペで動く最小コマンド
Node.js 20以上とGitが入っている前提です。create-nx-workspace は対話式でも使えますが、ここでは再現性を優先してオプションを全部明示します。コピペでそのまま動きます。
# 1. ワークスペースを作る(対話なしで再現性を確保)
npx create-nx-workspace@latest acme-nx \
--workspaceType=integrated \
--preset=apps \
--packageManager=pnpm \
--nxCloud=skip \
--interactive=false
cd acme-nx
# 2. ReactとNodeのプラグインを足す
pnpm nx add @nx/react
pnpm nx add @nx/node
# 3. アプリ3つを生成する
pnpm nx g @nx/react:app web \
--directory=apps/web --bundler=vite \
--unitTestRunner=vitest --style=css
pnpm nx g @nx/react:app admin \
--directory=apps/admin --bundler=vite \
--unitTestRunner=vitest --style=css
pnpm nx g @nx/node:app api \
--directory=apps/api --unitTestRunner=vitest
# 4. 共有ライブラリ3つを生成する
pnpm nx g @nx/react:lib ui \
--directory=libs/ui --unitTestRunner=vitest
pnpm nx g @nx/js:lib contracts \
--directory=libs/contracts --unitTestRunner=vitest
pnpm nx g @nx/js:lib config \
--directory=libs/config --unitTestRunner=none
# 5. まず依存グラフを目で見る
pnpm nx graph
ポイントは、Nxのジェネレーター(nx g)がファイルだけでなく project.json や tsconfig まで一貫して書き換えてくれる点です。手作業で設定をバラバラにしないで済みます。
最後の nx graph はブラウザで依存関係を線で見せてくれます。ここで「思ったより線が多いな」と感じたら、それは共通化しすぎのサインです。線が少ないほど、健康なモノレポです。
affectedをCIに入れる:全部走らせない勇気
ここが本題です。冒頭の12分を消します。
まずローカルで体感してみてください。main ブランチと今の作業を比べて、影響があるプロジェクトだけにタスクを流します。
# main との差分から、影響範囲だけ lint/test/build する
pnpm nx affected -t lint test build --base=main --head=HEAD
# 影響範囲をグラフで色付き表示する
pnpm nx graph --affected
libs/ui だけ直したなら、ui とそれを使う web・admin だけが対象になります。api は ui を使っていないので、最初から動きません。これが affected の効きです。
CIに入れるときの注意は2つだけ。1つ目、GitHub Actionsは履歴を浅く取るので、fetch-depth: 0 を入れないと差分比較に失敗します。2つ目、テストやlintを 必ずNx経由で呼ぶこと。vitest や eslint を直接叩くと、キャッシュもaffectedも効きません。Nxのグラフの外で動いてしまうからです。
name: nx-ci
on:
pull_request:
push:
branches: [main]
jobs:
affected:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 差分比較のため全履歴を取る
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
# origin/main との差分で、影響範囲だけ並列実行する
- run: pnpm nx affected -t lint test build --base=origin/main --head=HEAD --parallel=3
公式のnx affectedガイドでも、CIでは --base=origin/main --head=$PR_BRANCH_NAME のようにベースとヘッドを指定する形が示されています。NX_BASE / NX_HEAD の環境変数でも同じことができます。
チームで使うなら、リモートキャッシュ(Nx Cloud)も選択肢に入ります。誰かが回したビルド結果を他のメンバーやCIが使い回せるので、同じ作業を2度しなくなる。ただし最初は要りません。ローカルキャッシュと affected で十分に効果を確かめてから、CI時間が本当にボトルネックになったタイミングで足すのがいいです。
Claude Codeで大きなリポジトリを触るときの相性
ここが、僕がNxを手放せなくなった理由です。
Claude Codeに「モノレポを作って」とだけ頼むと、ファイルは増えます。でも初心者が本当に困るのは作った直後じゃなく、数週間後です。「apps/web を直したら apps/admin も壊れるのか」「この部品どこに置けばいいのか」が分からなくなる。
Nxがあると、この「分からない」を機械が答えてくれます。だからClaude Codeに渡す前に、まず境界を読ませます。
このNx Workspaceを初心者にも説明できる形で設計してください。
守る境界:
- apps/web と apps/admin は画面アプリ
- apps/api はAPI
- libs/ui は見た目だけのUI部品
- libs/contracts はAPIの型とZod schema
- libs/config はESLint、Vitest、TypeScript設定
- libs/* から apps/* へ依存しない
作業前に nx graph で依存関係を確認し、
変更後は nx affected で検証コマンドを出してください。
狙いは「実装して」を「境界を守って実装して」に変えることです。境界を先に渡すだけで、要らない共通化や横断修正がごっそり減ります。
project.json を編集させる前も、いきなり書き換えさせない。outputs(キャッシュ対象の出力場所)を壊すと、ビルドは成功しているのにキャッシュが効かない、という分かりにくい事故が起きます。
apps/web/project.json を読んで、build/test/serve の役割を
初心者向けに説明してください。
その後、変更が必要なら差分だけ提案してください。
outputs、cache、dependsOn は壊さないでください。
作業前に nx graph、作業後に nx affected -t test build。この2つをセットにするだけで、Claude Codeは「巨大リポジトリに何でも書くツール」から「影響範囲を説明できるレビュー役」に変わります。背景はClaude Codeのモノレポ管理、パッケージ分割の基礎はpnpm workspaceの実装も合わせて読むとつながります。
僕がNxでやらかした失敗3つ
正直に書きます。最初は失敗だらけでした。
ひとつ目は、libs/shared に何でも放り込んだこと。便利に見えて、3か月後には削れない依存の塊になっていました。今は新しい部品を作る前に「これはUI・型・設定・純粋関数のどれ?」と必ず自分に聞きます。どれにも当てはまらないなら、たぶんまだ共有する時期じゃない。
ふたつ目は、最初からライブラリを作りすぎたこと。アプリが2つしかないのに libs/auth・libs/domain・libs/data-access・libs/feature-* を量産して、機能追加よりフォルダ選びに時間を使う本末転倒に陥りました。最初は ui・contracts・config の3つで十分です。
みっつ目は、CIで pnpm test を直接叩いていたこと。Nxのグラフの外で走るので、キャッシュもaffectedも一切効かず、結局全部のテストが毎回フルで回っていました。pnpm nx affected -t test か pnpm nx run-many -t test に寄せた瞬間、CI時間が体感で半分以下になりました。
CI設計をもう少し広く整理したいなら、CI/CDのセットアップもどうぞ。
よくある質問
Q. 個人開発でもNxは要りますか? A. LP1枚と小さなAPIだけなら、普通の単一リポジトリのほうが速いです。Nxが効くのは、複数アプリが型やUIを共有し始めて、CIが重くなってからです。境界をまだ説明できない段階なら、先にリポジトリ地図の作り方で現状を整理するほうが先です。
Q. nx affected はどうやって「影響範囲」を判断していますか? A. Gitの差分(変更ファイル)と依存グラフを照らし合わせます。変更されたプロジェクトと、それに依存しているプロジェクトだけを対象に選びます。逆に、変更に依存していないプロジェクトは最初から除外されます。
Q. キャッシュが効いているか確認するには?
A. 同じタスクを2回続けて実行してみてください。2回目のログに「Nx read the output from the cache」のような表示が出れば、実行をスキップして保存済みの結果を返しています。出力先(outputs)の設定が正しいことが前提です。
Q. Nx CloudやリモートキャッシュはNxを使うのに必須?
A. いいえ。ローカルキャッシュと affected だけで大きな効果が出ます。Nx Cloudは「チームやCI間で結果を共有したい」ときの追加機能で、CI時間がボトルネックになってから検討すれば十分です。
Q. monorepoとNxは同じ意味ですか? A. 違います。monorepoは「複数プロジェクトを1リポジトリに置く」という置き方そのもの。Nxはそのmonorepoを速く・安全に管理する道具です。pnpm workspaceなど別の道具でmonorepoを運用することもできます。
実際に試した結果
Masaとして検証したときは、まず web・admin・api・ui・contracts だけを作って nx graph で依存線を確認しました。そのうえで libs/contracts の型を1つ変え、pnpm nx affected -t test build --base=main --head=HEAD を回した。すると、contractsに依存するアプリだけが対象になり、libs/ui だけを変えたときは api のビルドが対象外になることがはっきり見えました。
一番大きな気づきは、Nxの設定を暗記することじゃなかったです。グラフで境界を見てからClaude Codeに作業させると、変更がレビューできるサイズに収まる。冒頭の12分は、いまでは「色を変えたら web と admin だけ数十秒」になりました。
巨大なリポジトリを賢く触る前に、まず影響範囲を見える化する。遠回りに見えて、これが一番速い、というのが今の実感です。チームでClaude Code導入やモノレポ設計を標準化したいなら研修・相談も用意しています。まずは小さな検証リポジトリで上のコマンドを回し、nx graph のスクリーンショットを1枚残すところから始めてみてください。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
制作会社がClaude Codeに触らせる前に決める権限チェックリスト
クライアントサイトを壊さずにAI編集を使うための、制作会社向け権限と確認の型です。
SaaSサポートのバグ報告をClaude Codeで再現手順に変える実務フロー
問い合わせ文をそのまま開発へ投げず、再現手順、証拠、次の一手に整えるサポート向け手順です。
Obsidianの古いメモをClaude Codeの指示書に変える10分ルーチン
Obsidianに溜めたメモが毎回ゴミになる人へ。事実・決定・未確認に仕分けして、Claude Codeがそのまま動ける指示書に変える朝の10分の型を紹介します。