* feat(sbom): add `pnpm sbom` command (#9088) new command that generates SBOMs from the lockfile + store metadata. supports CycloneDX 1.6 JSON and SPDX 2.3 JSON via `--sbom-format`. two new packages following the existing `pnpm licenses` architecture: - `@pnpm/sbom` — core library (lockfile walking, store reading, serializers) - `@pnpm/plugin-commands-sbom` — CLI plugin wiring uses the lockfile walker for dependency traversal and reads package.json from the CAFS store for license/author/description metadata. `--lockfile-only` skips the store entirely for faster CI runs where metadata isn't needed. validated against official CycloneDX 1.6 and SPDX 2.3 JSON schemas. * chore: add sbom-related words to cspell dictionary * fix(sbom): address CycloneDX review feedback and bump to 1.7 Implements all 5 items from the CycloneDX maintainer review: split scoped names into group/name, move hashes to externalReferences distribution, use license.id for known SPDX identifiers, switch to modern tools.components structure with pnpm version, and bump specVersion to 1.7. Also adds spdx-license-ids for proper license classification and improves SPDX serializer test coverage. * fix(sbom): fix CI bundle failure for spdx-license-ids createRequire doesn't work in the esbuild bundle since it's a runtime resolve, switched back to regular import which esbuild can inline. * fix(sbom): use tarball URL for distribution externalReferences Use actual tarball download URL instead of PURL for CycloneDX distribution externalReferences, per review feedback. * feat(sbom): add CycloneDX metadata and improve SBOM quality scores adds $schema, timestamp, lifecycles (build/pre-build) to CycloneDX output to match what npm does. also enriches both CycloneDX and SPDX with metadata.authors, metadata.supplier, component supplier from author, vcs externalReferences from repository, and root component details (purl, license, description, author, vcs). SPDX now uses tarball URL for downloadLocation instead of NOASSERTION. renames CycloneDxToolInfo to CycloneDxOptions, passes lockfileOnly through to the serializer for lifecycle phase selection. adds store-dir to accepted CLI options. * fix(sbom): address CycloneDX review feedback round 2 switches license classification from spdx-license-ids to @cyclonedx/cyclonedx-library (SPDX.isSupportedSpdxId) for accurate CycloneDX license ID validation per jkowalleck's feedback. removes hardcoded metadata.authors and metadata.supplier — these are not appropriate for a tool to set. adds --sbom-authors and --sbom-supplier CLI flags so the SBOM consumer (e.g. ACME Corp) can declare who they are. removes supplier from components — supplier is the registry/distributor, not the package author. also fixes distribution externalReference to only emit when a real tarball URL exists, no PURL fallback. * fix(sbom): use sub-path import for CycloneDX library to fix bundle top-level import from @cyclonedx/cyclonedx-library drags in validation/serialize layers with optional deps (ajv-formats, libxmljs2, xmlbuilder2) that esbuild can't resolve during pnpm CLI bundling. switch to @cyclonedx/cyclonedx-library/SPDX which only pulls in the SPDX module we actually use — pure JS, no optional deps. * chore: update manifests * refactor: extract shared store-reading logic into @pnpm/store.pkg-finder Both @pnpm/license-scanner and @pnpm/sbom independently implemented nearly identical logic to read a package's file index from the content-addressable store. This extracts that into a new shared package that returns a uniform Map<string, string> (filename → absolute path), simplifying both consumers. Close #9088 --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
简体中文 | 日本語 | 한국어 | Italiano | Português Brasileiro
Fast, disk space efficient package manager:
- Fast. Up to 2x faster than the alternatives (see benchmark).
- Efficient. Files inside
node_modulesare linked from a single content-addressable storage. - Great for monorepos.
- Strict. A package can access only dependencies that are specified in its
package.json. - Deterministic. Has a lockfile called
pnpm-lock.yaml. - Works as a Node.js version manager. See pnpm env use.
- Works everywhere. Supports Windows, Linux, and macOS.
- Battle-tested. Used in production by teams of all sizes since 2016.
- See the full feature comparison with npm and Yarn.
To quote the Rush team:
Microsoft uses pnpm in Rush repos with hundreds of projects and hundreds of PRs per day, and we’ve found it to be very fast and reliable.
Platinum Sponsors
|
|
Gold Sponsors
|
|
|
|
|
|
|
|
|
|
|
Silver Sponsors
|
|
|
|
|
|
|
|
Support this project by becoming a sponsor.
Background
pnpm uses a content-addressable filesystem to store all files from all module directories on a disk. When using npm, if you have 100 projects using lodash, you will have 100 copies of lodash on disk. With pnpm, lodash will be stored in a content-addressable storage, so:
- If you depend on different versions of lodash, only the files that differ are added to the store.
If lodash has 100 files, and a new version has a change only in one of those files,
pnpm updatewill only add 1 new file to the storage. - All the files are saved in a single place on the disk. When packages are installed, their files are linked from that single place consuming no additional disk space. Linking is performed using either hard-links or reflinks (copy-on-write).
As a result, you save gigabytes of space on your disk and you have a lot faster installations!
If you'd like more details about the unique node_modules structure that pnpm creates and
why it works fine with the Node.js ecosystem, read this small article: Flat node_modules is not the only way.
💖 Like this project? Let people know with a tweet
Getting Started
Benchmark
pnpm is up to 2x faster than npm and Yarn classic. See all benchmarks here.
Benchmarks on an app with lots of dependencies: