下面两个字段都提到了 pnpm,但职责不同:

{
  "packageManager": "pnpm@11.0.0",
  "engines": {
    "node": ">=24.0.0",
    "pnpm": ">=11.0.0"
  }
}

packageManager 用于声明项目实际采用的包管理器及精确版本。Corepack,以及支持自管理版本的新版 pnpm,都能读取它并运行 pnpm 11.0.0。

engines.pnpm 表达的是兼容范围:这个项目允许哪些 pnpm 版本。它本身不负责选择或下载某个具体版本。pnpm 在本地项目根目录发现自身版本不匹配时会报错;当该包作为依赖安装时,除非启用 engineStrict,通常只产生警告。

可以把两者理解为:

packageManager  → 这次应该运行哪个版本
engines.pnpm    → 哪些版本被项目认为兼容

如果项目要求所有开发者和 CI 完全一致,并且执行入口已经启用 Corepack 或 pnpm 的自管理能力,只写 packageManager 通常已经足够:

{
  "packageManager": "pnpm@11.21.0"
}

需要向部署平台或其他工具额外声明兼容边界时,再补充 engines。两者同时存在时,应保证精确版本落在兼容范围内,否则会产生自相矛盾的配置。

同理,engines.node 只是 Node.js 兼容范围;真正希望开发者进入目录就自动切换 Node.js 时,仍建议提交 .node-version.nvmrc

参考:Node.js packageManagerpnpm engines