Safeguard
Developer Tools•

Lock file or manifest: what should a build time dependency scan read?

Scan the lock file, not just the manifest. It records the exact versions that ship, including transitive packages that a manifest range leaves open.

Safeguard Security Team
4 min read

A build time dependency scan should read the lock file, because it records the exact versions that will be installed, including transitive ones. A manifest holds ranges, so a scan of it alone can describe a different tree from the one you ship. Use the manifest only as a fallback.

Definitions

A manifest (package.json, requirements.txt, pom.xml and similar) lists what you asked for, often as version ranges. A lock file records what the resolver actually chose, version by version, for direct and transitive packages. A scan is only as accurate as the list it reads.

What the npm docs confirm

npm's clean install command is built for automated environments. It requires an existing package-lock.json or npm-shrinkwrap.json, errors if the lock file and package.json disagree, never writes to either file, and removes any existing node_modules first. Those are exactly the properties a build time scan wants: a frozen, repeatable input.

The audit command goes further. By default it requires a package lock or shrinkwrap to run, and the documentation warns that bypassing the lock means results may differ on every run, because npm rebuilds the dependency tree each time.

pip works differently. Its documentation says hash checking mode needs all requirements pinned and hashed, and that every dependency must be spelled out in the requirements file. A fully pinned and hashed file plays the lock file's role there.

Comparison

InputStrengthWeakness
Manifest onlyAlways presentRanges, so the scanned tree may not match the shipped one
Lock fileExact versions, transitive includedNeeds to be committed and kept current
Resolved install in CIReflects realityScan happens after the install
Built artifact or imageShows what actually shippedLater in the process, harder to attribute to a change

Steps to get this right

  1. Commit lock files for applications. For libraries, follow your ecosystem's guidance, but still resolve a full tree in CI.
  2. Install in CI with the frozen command so a mismatch fails the build instead of silently updating.
  3. Point the scanner at the lock file, and check that it lists transitive packages.
  4. Store the scan output, or an SBOM generated from the same tree, with the build.
  5. For container builds, scan the final image too, since system packages are not in an application lock file.

Common mistakes

  • Scanning before install and after a later update. If a step modifies the tree after the scan, the result is stale.
  • Ignoring dev dependencies. They run in CI and on laptops. Decide on purpose whether to include them.
  • Treating "no lock file" as fine. It means your scan results are not reproducible.

Try it yourself

Click through it at your own pace, or open it full screen. Compare the direct dependencies with the transitive ones that make up most of the inventory.

Where Safeguard fits

Safeguard performs dependency scanning and SBOM generation from your project files and builds, and you can try it free at gold.safeguard.sh/scan. For a related comparison, see runtime SBOM vs build time SBOM.

Quick check

Is a manifest scan useless without a lock file?

Not useless, but approximate. It reflects ranges, so treat results as indicative and add a lock file to make them exact.

Do I need to scan both the lock file and the image?

For containers, yes. The lock file covers application packages. The image adds operating system packages and anything copied in during the build.

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.