A pnpm catalog is a named list of dependency version ranges kept in pnpm-workspace.yaml. Packages in the workspace reference an entry with the catalog: protocol instead of repeating the range. You change one line to move every package that uses that dependency, which keeps versions consistent and upgrade diffs small.
The problem catalogs solve
In a monorepo with twenty packages, react or typescript may be declared twenty times. Over a year the ranges drift. One package sits on an old minor, another on a newer one, and you end up shipping two copies or debugging a conflict that only shows up at runtime.
The pnpm documentation lists three benefits: a single version per dependency, simpler upgrades because one catalog entry updates every consumer, and fewer merge conflicts because upgrades stop touching many package.json files.
The default catalog
Define it with the singular catalog key in pnpm-workspace.yaml:
catalog:
react: ^18.2.0
react-dom: ^18.2.0
Then, in any workspace package, use the protocol in place of a range:
"dependencies": {
"react": "catalog:"
}
Both catalog: and catalog:default point at the default catalog.
Named catalogs
When you cannot move everything at once, define named catalogs under the plural catalogs key:
catalogs:
react17:
react: ^17.0.2
react18:
react: ^18.2.0
A package opts in with "react": "catalog:react18". This lets a legacy app stay on the old major while new packages move ahead, and the split is visible in one file. A default catalog can sit next to named ones.
Where the protocol works
According to the pnpm docs, the protocol is allowed in dependencies, devDependencies, peerDependencies and optionalDependencies, and also in overrides inside pnpm-workspace.yaml. When you run pnpm publish or pnpm pack, pnpm swaps catalog: for the real range, so a published package does not carry a reference that only your workspace understands.
Why this helps security review
One file now holds the intended version of every shared dependency. A reviewer who sees a one line change to a catalog knows it affects every package that references it, and can ask for the blast radius before approving. Pair the file with a code owner rule, described in our post on code owners for dependency manifests.
A catalog sets ranges, not locked versions. The resolved versions still live in pnpm-lock.yaml, so commit that file as well. See what a lockfile is and why to commit it.
What it does not do
A catalog does not stop two packages from needing incompatible versions. It makes that choice explicit. It also covers only dependencies you list in it, so packages can still declare their own ranges for everything else.
Safeguard dependency and SBOM scanning can list the packages in each part of a repository and flag known vulnerabilities. You can try a free scan at gold.safeguard.sh/scan.
Click through it at your own pace, or open it full screen.
Quick check
Does a catalog replace the lockfile?
No. The catalog holds version ranges. The lockfile records the exact versions pnpm resolved from them.
What happens to catalog: references when I publish?
pnpm replaces them with the actual version range on publish and pack, so consumers outside the workspace see normal ranges.
Sources
Last reviewed: 19 October 2026.