10
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

スケーラブルなMonorepo設計入門:Turborepo × pnpm(NestJS + Next.js + Prisma)

10
Last updated at Posted at 2026-04-07

🧩 はじめに

複数のアプリケーション(API / Web)と、共通ロジック(DB / UI / 型 / 設定)を
1つのリポジトリで管理したい場合、Monorepoは非常に有効な選択肢です。

しかし、設計を誤ると以下のような問題が発生します:

  • ❌ ビルドが遅い
  • ❌ DTOが重複する(Backend / Frontend)
  • ❌ Prisma schemaが分散する
  • ../../packages/... のimport地獄
  • ❌ スケールしない構成

🎯 本記事のゴール

以下の構成で、実務レベルのMonorepo設計を理解します:

  • Turborepo
  • pnpm workspace
  • NestJS(Backend)
  • Next.js(Frontend)
  • Prisma + PostgreSQL

🏗️ 全体構成

apps/
  api/        # NestJS(Backend)
  web/        # Next.js(Frontend)

packages/
  api/        # API contract(DTO / 型)
  database/   # Prisma(schema / client)
  ui/         # UIコンポーネント
  config/     # 共通設定(eslint / tsconfig)

📦 pnpm workspace

# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"

👉 apps / packages を明確に分離することで、責務をコントロールできる


🔥 最重要:Boundary(境界設計)

Monorepoで最も重要なのは ツールではなく設計 です。


🧱 レイヤー定義

レイヤー 役割
apps 実行される場所(runtime)
packages 再利用可能なロジック

📌 apps の責務

  • Controller
  • Routing
  • DI(Dependency Injection)
  • Server起動

📌 packages の責務

  • 型(DTO)
  • DB client
  • UI
  • 共通設定

⚠️ 境界が崩れると…

  • DTOが重複する
  • Prisma schemaが複数存在する
  • importが複雑になる
  • 保守性が崩壊する

👉 Monorepoの成否はBoundaryで決まる


🔗 workspace: による内部依存


🧩 apps/api(NestJS)

"dependencies": {
  "@repo/api": "workspace:*",
  "@repo/database": "workspace:*"
}

👉 APIは以下に依存:

  • API contract(型)
  • DB client

🧩 apps/web(Next.js)

"dependencies": {
  "@repo/ui": "workspace:*",
  "next": "16.x",
  "react": "^19.x"
},
"devDependencies": {
  "@repo/api": "workspace:*"
}

💡 ポイント

  • UI → runtime依存
  • API contract → 型のみ(devDependencies)

👉 Frontendは「型だけ欲しい」が多い


📦 @repo/api(API Contract)

🎯 役割

  • DTO / Response型を管理
  • 実行しない(pure library)

package.json

{
  "main": "./dist/entry.js",
  "types": "./dist/entry.d.ts",
  "exports": {
    ".": {
      "import": "./dist/entry.js"
    }
  }
}

scripts

{
  "scripts": {
    "dev": "pnpm build --watch",
    "build": "tsc -b"
  }
}

👉 libraryとしてビルドするのがポイント


🗄️ @repo/database(Prisma集約)

🎯 ベストプラクティス

👉 DB関連はすべてここに集約

packages/database/
  prisma/
    schema.prisma
  src/
    client.ts
    seed.ts

scripts

{
  "scripts": {
    "build": "prisma generate && tsc",
    "db:migrate:dev": "prisma migrate dev",
    "db:migrate:deploy": "prisma migrate deploy",
    "db:push": "prisma db push",
    "db:seed": "tsx src/seed.ts",
    "generate": "prisma generate"
  }
}

🔥 なぜ重要?

  • ✅ schemaが一元管理される
  • ✅ migrationの衝突を防げる
  • ✅ APIはclientを使うだけ
  • ✅ チーム開発に強い

⚡ Turborepo Task設計(超重要)

turbo.json

{
  "tasks": {
    "dev": {
      "cache": false,
      "persistent": true
    },
    "build": {
      "dependsOn": ["^build", "^generate"],
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": [".next/**", "dist/**"]
    },
    "db:migrate:dev": { "cache": false },
    "db:seed": { "cache": false },
    "generate": {
      "dependsOn": ["^generate"],
      "cache": false
    },
    "lint": {},
    "test": {}
  }
}

🔑 ポイント解説

① dependsOn

"dependsOn": ["^build", "^generate"]

👉 依存順で実行:

packages → apps

② cache戦略

Task Cache
build
dev
DB系

③ outputs

"outputs": [".next/**", "dist/**"]

👉 キャッシュ対象を明確化


④ .env を含める

"inputs": ["$TURBO_DEFAULT$", ".env*"]

👉 環境差によるキャッシュバグ防止


🧪 root scripts

{
  "scripts": {
    "dev": "turbo run dev",
    "build": "turbo run build",
    "db:migrate:dev": "turbo run db:migrate:dev",
    "db:seed": "turbo run db:seed",
    "lint": "turbo run lint",
    "test": "turbo run test"
  }
}

🔄 運用フロー

🚀 開発

pnpm dev

🏗️ ビルド

pnpm build

🗄️ DB操作

pnpm db:migrate:dev
pnpm db:seed
pnpm db:push

✅ 品質チェック

pnpm lint
pnpm test

💡 この構成の強み

  • ✅ DTOの重複を防ぐ → @repo/api
  • ✅ Prismaの一元管理 → @repo/database
  • ✅ 高速ビルド → Turborepo cache
  • ✅ スケーラブル → 明確なBoundary

⚠️ よくあるミス


❌ DBタスクをキャッシュする

"cache": false

👉 データ不整合の原因になる


❌ .envをinputsに含めない

👉 キャッシュバグ発生


❌ @repo/api が DB に依存する

api → database ❌

👉 Boundary崩壊


🧠 まとめ

重要なのは「Turborepoの速さ」ではありません。


🔥 本質

👉 Boundary設計 × Task設計


🧩 最終原則

  • apps = runtime
  • packages = shared
  • dependency = workspace:*
  • Prisma = @repo/database
  • DTO = @repo/api
  • Turbo = build + cache管理
10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?