Safeguard
Developer Tools•

Yarn Plug'n'Play has no node_modules: what do SBOM tools read?

With Yarn PnP there is no node_modules folder, so folder based scanners can report nothing. Check that your SBOM tool reads yarn.lock and test the result.

Safeguard Security Team
6 min read

With Yarn Plug'n'Play a project has no node_modules folder, so a scanner that walks that folder may find nothing. Use a tool that reads the lockfile, then check the component count against your expectations. If the count is zero or tiny, the tool is looking in the wrong place.

What PnP changes

The Yarn documentation says Plug'n'Play is the default installation strategy in modern releases of Yarn. A PnP project lacks a node_modules folder. Yarn generates a single Node.js loader file, named .pnp.cjs, that holds the dependency tree so tools can find packages on disk. It references packages directly through their cache path instead of copying them into the project. The docs add that PnP can be replaced with node_modules or pnpm style symlinks.

So the shape of the filesystem is different from what many scanners expect.

Which input should an SBOM tool use?

InputAvailable under PnP?Notes
node_modules folderNo, by defaultScanner finds nothing
yarn.lockYesRecords resolved packages
package.jsonYesDeclared ranges, not resolved
.pnp.cjsYesDependency tree as Yarn resolved it

Lockfile based detection is the usual answer. Microsoft's open source component detection project, for example, lists NPM support as including Yarn and pnpm, though its page does not describe per detector details, so test your own tool and do not assume.

A five step test

  1. Count the packages in the lockfile. Look at the number of resolved entries.
  2. Generate the SBOM.
  3. Count components, excluding the root.
  4. Compare. They should be close, with differences you can explain, such as one lockfile entry serving several ranges.
  5. Spot check three transitive packages by name.

If you see zero components, the tool probably walked the folder. Switch its mode or its input, or change the Yarn linker to node_modules for the scan job.

The linker option

Changing the linker for CI just is a fair workaround. It means installing in a scan job with the node_modules strategy so folder based tools see packages. The tradeoff is that the scanned tree is not the one you deploy, so your SBOM describes a close cousin. Prefer lockfile input if the tool supports it.

Pitfalls

Yarn classic and modern Yarn write differently formatted lockfiles, so a tool must support the one you use. Resolutions and patches can change what is actually installed. Check that those show up. And treat dev dependencies carefully: decide whether the file is for production or for review.

A worked example

A team migrates a service from a node_modules based install to Plug'n'Play. Before the move, their SBOM job walked the node_modules folder and reported about 800 components. After the move, the same job reports 3. The numbers are illustrative. Nothing about the application's dependencies changed, but the filesystem layout did.

The investigation goes like this:

  1. Check that the lockfile still exists and still lists the packages. It does.
  2. Look at the project directory. There is no node_modules folder, and a .pnp.cjs file sits in its place, as the Yarn documentation describes.
  3. Read the SBOM tool's docs. It scans installed folders by default.
  4. Switch the tool to lockfile input, or point it at the lockfile explicitly.
  5. Rerun. The count returns to roughly the same number as before.

The lesson is that a drop in count after a tooling change is a signal, not a success.

What each input tells you

InputStrengthWeakness
LockfileExact resolved versions, works without installDoes not show what is on disk
Package manifestDeclared intentRanges, not resolved versions
Loader fileWhat Yarn resolved for NodeNot a standard SBOM format
Installed folderWhat a classic install put on diskAbsent under PnP

Lockfile input is the practical choice. It works in CI without a full install and gives resolved versions.

The node_modules linker as a fallback

The Yarn docs say PnP can be replaced by node_modules or pnpm style symlinks. If a scanning tool cannot read the lockfile, you can run the scan job with a node_modules install. Be aware that the scanned tree then differs from what you deploy, so note this in the SBOM metadata.

Checks to build into the job

  1. Compare the SBOM component count with the number of resolved entries in the lockfile, with a tolerance you can explain.
  2. Fail the job if the count is below a floor taken from the last release.
  3. Spot check that a few well known transitive packages are present.
  4. Verify that dev dependencies are marked or excluded as you intend.
  5. Record the Yarn version and the linker mode in the file's metadata.

Patches and resolutions

Modern Yarn lets a project patch packages and force versions of transitive dependencies. Those changes affect what runs. Check that your SBOM reflects the patched or forced version, and note the patch. If the tool reads solely the manifest, it may show the original range.

Zero installs

Some teams commit the package cache to the repository. If yours does, the repository itself contains the dependency archives. That is convenient for reproducibility, but it also means large diffs on updates and a need to review changes to binary archives. Your SBOM review should include the lockfile diff as the readable summary of what changed.

Communicating limits

If you ship an SBOM generated from the lockfile, say so in the cover note. Readers who expect an installed tree should know the file describes resolved versions, not a scan of disk.

Where Safeguard fits

Safeguard scans dependencies and SBOMs. To see how your lockfile reads, try the free scan at gold.safeguard.sh/scan on a PnP project and compare the count.

Try it yourself

Click through it at your own pace, or open it full screen.

Click into a few components and note how direct and transitive packages are separated.

Quick check

Why does my scan of a Yarn project show zero packages?

Under PnP there is no node_modules folder. The tool may be reading that folder. Use lockfile input.

Is .pnp.cjs an SBOM?

No. It is a loader holding the resolved tree for Node, not a bill of materials in a standard format.

Do I need to switch away from PnP to get an SBOM?

No. Use a tool that reads the lockfile. Switching the linker is a fallback for tools that cannot.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.