If you work with JavaScript or TypeScript, pnpm is a strong choice due to its efficient package management without any configuration step. What really makes this tool stand out is the myriad of extra features. Case in point: At work, we're consolidating several large web repositories into a single monorepo. Some of these repositories are already monorepos themselves, which results in many package.json files with overlapping dependencies and differing versions.
Simplifying that maintenance typically requires some form of centralized dependency management, often with some kind of software bill of materials (SBOM). pnpm supports this via its Catalogs feature. The feature is so flexible that it allows you to support either a single-version policy, or multiple versions of dependencies.
Rather than duplicating pnpm's documentation, I'll show how I enabled this feature in a small personal project.
First, you need to create a catalogue section in your workspace file, pnpm-workspace.yaml (source):
catalog:
"@types/chai": 5.2.3
"@types/node": 24.10.1
chai: 6.2.1
typescript: 5.9.3
And then, you simply replace your dependencies, devDependencies and related, in your package.json files, like this (source):
From:
"devDependencies": {
"@types/chai": "5.2.3",
"@types/node": "24.10.1",
"chai": "6.2.1",
"typescript": "5.9.3"
},
To:
"devDependencies": {
"@types/chai": "catalog:",
"@types/node": "catalog:",
"chai": "catalog:",
"typescript": "catalog:"
},
At this point, running pnpm install completes the setup. However, additional configuration is required when using Bazel. If you run this through Bazel, you will face a rules_ts error trying to resolve typescript's version as catalog:. Thankfully, the fix is simple, as rules_js exposes a way to query the resolved version of any Bazel-managed npm dependency.
In your MODULE.bazel, when you configure the rules_ts extension to tell it where to pick TypeScript's version from, change the following (source):
From:
rules_ts_ext.deps(
ts_version_from = "//:package.json",
)
To:
rules_ts_ext.deps(
ts_version_from = "@npm//:typescript/resolved.json",
)
pnpm's lockfile, pnpm-lock.yaml, already contains the resolved versions of all dependencies, so rules_js fully supports the pnpm catalogs feature. When you face tooling that relies on analyzing package.json, like rules_ts's special treatment of the typescript dependency, you need to resort to alternatives. The solution is straightforward and avoids compromising the benefits of using pnpm catalogs.