Nexjs:turborepo
2026年8月14日monorepo
my-repo/
├─ apps/
│ ├─ web/ ← Next.js アプリ
│ └─ admin/ ← 管理画面アプリ
├─ packages/
│ └─ ui/ ← 共通コンポーネント
└─ package.json1つのフォルダで複数アプリを管理できるという理由で異なる(サブ)ドメインのアプリを詰め込まない方が良い。
tsconfigやpackage.jsonの知識が浅いとturborepoを活用しきれないと感じた。monorepoでは
npmではなくpnpmというパッケージ管理を使う。Vercelでのデプロイ:
apps/webやapps/adminのようにアプリ別にデプロイできる以下の呼び方で統一
App:appsフォルダの中の各アプリ
内部パッケージ:packagesフォルダ内のパッケージ
パッケージ:App・内部パッケージに関わらず
package.jsonがある場合はパッケージ
pnpm
pnpm add ライブラリでインストールしたライブラリはインストールコマンドを実行したパッケージ内のpackage.jsonに依存として記載されるが、ライブラリの実体はUbuntuだと~/.local/share/pnpm/storeにある。各パッケージでそのライブラリを使いたい場合、各パッケージ内の
node_modulesにシンボリックリンクが存在しなければ importできないので、パッケージ側でもpnpm add ライブラリコマンドが必要

pnpm自体のインストール:
npm install -g pnpm
pnpmを使ったライブラリのインストール:
パッケージ内で
pnpm addライブラリ
アプリの起動:
ルートから
pnpm devをするとすべてのアプリが3000ポートから順に開かれるcdでアプリに移動してpnpm devをすると該当アプリのみが起動
package.json: script
"dev:web": "turbo dev --filter=./apps/web",
"dev:admin": "turbo dev --filter=./apps/admin" cdコマンドで各アプリに移動して起動したくない場合
turbo.json:ターミナル
{
"$schema": "https://turbo.build/schema.json",
"ui": "stream",ターミナルのUIは
streamが見やすい
依存関係のupdate:
# ^4.17.15なら4の範囲内
pnpm -r update
# major(一番左の数字)も更新
pnpm -r update -L-r:recursive(再帰的)-L:latest
turborepo
https://turborepo.com/docs/guides/
pnpm dlx shadcn@canary init最初から shadcn と tailwind の設定がされている
packageの作成
https://turborepo.dev/docs/crafting-your-repository/creating-an-internal-packageを参考
// apps/web/package.json
"dependencies": {
"@repo/ui": "workspace:*",
"@repo/functions": "workspace:*",重要:dependenciesに手書きでpackageを書き足した場合、
pnpm iを実行してapps側のnode_modulesにシンボリックリンクを作成する。
❯ pnpm i
Scope: all 8 workspace projects
../.. | Progress: resolved 308, reused 277, downloaded 0, added 0, d
one
dependencies:
+ @repo/functions 1.0.0 <- ../../packages/functions環境変数
環境変数をapps内の .env に追加してprocess.env. で使おうとすると以下のような警告が出る
GLOBAL_ENV_TEST is not listed as a dependency in root turbo.jsoneslintturbo/no-undeclared-env-vars
string | undefined
警告を出しているのはスターターで作成されたpackages/eslint-config/base.jsの設定
// packages/eslint-config/base.js
rules: {
"turbo/no-undeclared-env-vars": "warn",
},turbo.json の"env" 配列に環境変数を追加すると消える。
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"],
"env": ["SECRET_FROM_DOCS_APP", "GLOBAL_ENV_TEST"]
},turbo.jsonについて:
関係があるのはローカルでビルドコマンドを実行した時
turboはコードが変わっていない場合、過去にビルドした結果を環境変数の値も含め古いビルドキャッシュを使い回す。turbo.jsonの"env"に環境変数名を追加する必要があるのは.envを書き換えたのにビルド時に反映されない事を避ける為。= 追加した環境変数の値が変わるとビルドキャッシュは破棄される。
Vercelのデプロイ設定
最初からturborepoで作り始めた場合は何もしなくていい。
途中からプロジェクトをturborepoにした場合、Vercelのアプリダッシュボード/settings/build-and-deploymentから任意のアプリ(apps)のパスを入力し、以下2つの項目にチェックを入れる。
Include files outside the root directory in the Build Step.
Skip deployments when there are no changes to the root directory or its dependencies.上の方は設定したルート(
apps/web)外のファイルもビルドコンテキストに含める設定。turborepoは設定したルート以外のpackageからもファイルを参照する為チェックが必要下の方はルートディレクトリに設定したアプリに変更がない場合、他のアプリに変更があっても再デプロイしない設定
Vercelのデプロイ時間制限に引っかかるのを避ける為に必要
Prismaをpackagesに分ける
packages/dbにPrismaの機能をすべて分ける、generateで生成された型とPrismaのインスタンス化ファイルをexportし apps側でimportして使う。
セッティングは省略
使い方で重要なのはスクリプトコマンド
// packages/db/package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"db:pull": "dotenv -e .env.development -- npx prisma db pull",
"db:push": "dotenv -e .env.development -- npx prisma db push",
"db:generate": "dotenv -e .env.development -- npx prisma generate",
"db:deploy": "dotenv -e .env.development -- npx prisma migrate deploy",
"db:migrate": "dotenv -e .env.development -- npx prisma migrate dev",
"db:studio": "dotenv -e .env.development -- npx prisma studio",
},// ルートのpackage.json
"db:web:generate": "pnpm --filter @workspace/db-web db:generate",
"db:web:migrate": "pnpm --filter @workspace/db-web db:migrate"
---
// apps/~のpackage.json
"db:generate": "pnpm -F @workspace/db-web db:generate",
"db:migrate": "pnpm -F @workspace/db-web db:migrate",
"db:studio": "pnpm -F @workspace/db-web db:studio",
"vercel-build": "pnpm -F @workspace/db-web db:generate && pnpm -F @workspace/db-web db:deploy && next build",ルート・apps側、どちらからPrismaのCliコマンドを実行する場合も呼び出すのは
packages/dbのスクリプトコマンドになる。
"vercel-build": "pnpm -F @workspace/db-web db:generate && pnpm -F @workspace/db-web db:deploy && next build",apps/~のpackage.jsonに記載した上記はVercelがビルド時に使うビルドコマンド。Vercelはダッシュボードでoverrideされたコマンドが無ければ、vercel-buildコマンド > buildコマンド の優先度
新しく apps/~を作成し、それが既存のpackages/db-と別のDB_URL/schemaを使う場合、packages/db-xxxを新たに作成する。
エラー
ローカルでのビルドエラー
Prisma
ローカルでPrisma関連のビルドエラーが出た時の対策:
"compilerOptions": {
"declaration": false,
"declarationMap": false,アプリ内の
tsconfig.jsonに上記を書く。
falseにしても大丈夫化なのか
declarationは型定義ファイル
.d.tsを生成するオプションパッケージとして配布したい場合は影響が出るが、apps側には関係無い。
Vercelデプロイ時のエラー
pnpm
エラー内容( Vercel log ):
ERR_PNPM_OUTDATED_LOCKFILE
Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date原因:同期のズレ
apps側で誤ってnpm iでライブラリを追加するとpnpm.lock.ymlは更新されないので同期がズレる。あるいは手動で
apps側のpackage.jsonのバージョン更新をした後にpnpm i を忘れるなど。
対策:
ルートにある
pnpm-lock.yaml,node_modules,.turboを削除したあとに、pnpm iをする。