はじめに
Turborepo はモノレポ向けのビルドツールである。試しに以下のコマンドでプロジェクトを作成したところ、
pnpm create turbo@latest myapp --package-manager pnpm
生成された package.json には以下のエントリが含まれていた。
{ ... "packageManager": "pnpm@9.0.0", ... }
本記事の執筆時点における pnpm の最新バージョンは 11.14.0 である。そのため、この値を 11.14.0 に書き換えようと packageManager エントリの仕様を調べたところ、この設定はもともと Node.js の Corepack のために策定された仕様であること、さらに Node.js 25 から Corepack が同梱されなくなることが分かった。
そこで本記事では、package.json のルートに記述する packageManager と、新たに導入された devEngines.packageManager の違いについて整理する。
1. そもそもルートの packageManager とは
package.json のトップレベル(ルート)に記述する "packageManager": "pnpm@9.0.0" のような設定は、もともと Node.js に同梱されていたツール Corepack のために策定された仕様である。
npm のドキュメントに記載されていない理由
npm は Corepack を介さず単体で動作するという設計思想を採用している。そのため、npm 公式の package.json ドキュメントには、このルートの packageManager エントリは記載されていない。実際、npm 単体ではこの設定を参照しない。
一方、pnpm や Yarn は Corepack が存在しない環境でも、このエントリを独自に解釈して使用するパッケージマネージャーのバージョンを切り替える機能を実装した。その結果、現在では packageManager は Corepack 以外でも広く利用されるようになっている。
ルート packageManager の限界
ルートの packageManager には、「バージョンを単一の固定値でしか指定できない」という制限がある。
例えば、以下のような指定は可能である。
"packageManager": "pnpm@9.0.0"
しかし、以下のようなセマンティックバージョニング(SemVer)による範囲指定は行えない。
^9.0.0 >=11.0.0
この柔軟性の欠如が、後述する devEngines が提案された背景の一つとなっている。
2. 新しい標準 devEngines の登場
ルートの packageManager が抱える制約を解消し、エコシステム全体で統一的に利用できる仕組みとして、OpenJS Foundation が主導して提案したのが devEngines である。
{ "devEngines": { "packageManager": { "name": "pnpm", "version": "^11.0.0", "onFail": "error" } } }
devEngines のメリット
devEngines には次のような利点がある。
バージョン範囲を指定できる
"version": "^11.0.0"のように、SemVer を用いた柔軟な指定が可能である。不一致時の動作を制御できる
バージョンが一致しない場合に、エラー (
error)・警告 (warn)・自動ダウンロード (download) などの挙動をonFailで指定できる。実行環境をまとめて管理できる
パッケージマネージャーだけでなく、Node.js などのランタイムのバージョンも同じ場所で管理できる。
3. 現時点での対応方法
現時点では、devEngines の対応状況はツールによって異なる。そのため、互換性を重視するのであれば、やや冗長ではあるものの、以下のように両方を記述しておくのが無難である。
{ "packageManager": "pnpm@11.14.0", "devEngines": { "packageManager": { "name": "pnpm", "version": "^11.14.0" } } }
一方、最新の npm や pnpm は devEngines に対応している。そのため、これらのツールのみを対象とするプロジェクトであれば、packageManager を省略し、devEngines のみを記述してもよい。
{ "devEngines": { "packageManager": { "name": "pnpm", "version": "^11.14.0" } } }
まとめ
- ルートの
packageManagerは Corepack のために策定された従来の仕様である。 - Node.js における Corepack の同梱終了を見据え、エコシステムは
devEnginesへの移行を進めている。 - 最新の npm や pnpm を利用するのであれば、
devEnginesを利用するだけで十分な場合が多い。