Safeguard
Supply Chain•

save-exact or a lockfile: which one pins your npm dependencies?

save-exact pins the versions written to package.json, while the lockfile pins the whole tree. What each covers, and why most Node apps need the lockfile.

Safeguard Security Team
3 min read

They pin different things. save-exact makes npm write exact versions for the packages you add to package.json. The lockfile records the resolved versions for the whole tree, including transitive packages. For an application, the committed lockfile with npm ci does the real pinning, and save-exact is an extra.

What each setting does

The npm config reference defines save-exact as a boolean, default false: saved dependencies get an exact version rather than npm's default semver range operator. It applies when you run an install that saves a dependency.

The npm ci documentation describes the lockfile side. The command needs a package-lock.json or npm-shrinkwrap.json, errors if the lock and package.json disagree instead of updating the lock, deletes an existing node_modules, and never writes to package.json or the lockfile. The docs call such installs essentially frozen.

Side by side

Questionsave-exactCommitted lockfile with npm ci
Pins direct dependenciesYes, when savingYes
Pins transitive dependenciesNoYes
Works for packages already in package.jsonNo, only new savesYes
Fails the build if versions driftNoYes, on a mismatch
Affects consumers of a libraryYes, stricter rangesNo, package-lock.json is not in the published tarball

The last row matters for libraries. The npm package.json docs list lockfiles such as package-lock.json among the files always left out of the tarball, so a library's lockfile does not control what its users install.

Why save-exact alone falls short

Most supply chain incidents arrive through transitive packages. An exact version on your direct dependency still allows that dependency's own ranges to resolve to a newer release on a fresh install. Without a lockfile, two installs on different days can differ.

What to do

  1. Commit the lockfile and use npm ci in CI and in image builds.
  2. Optionally set save-exact=true in .npmrc, so new additions are visible as exact numbers in review. This is a style choice with a small benefit.
  3. Review lockfile changes in pull requests. See what to check in a lockfile diff.
  4. Update on a schedule, not by accident. Pair updates with a release delay such as dependency cooldown periods.
  5. Do not set package-lock=false for an application. The config page says that setting makes npm ignore existing lockfiles and stop writing them.

What neither one proves

Pinning controls what you get, not whether it is safe. A pinned malicious version stays malicious. You still need scanning of the pinned tree.

Try it yourself

Open the dependency inventory demo and see how a scan lists every package in a tree, including transitive ones that save-exact never touches.

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

Safeguard builds SBOMs and scans the full dependency tree from your lockfile. Start with a free scan.

Quick check

Does save-exact change packages already in package.json?

No. It affects how new saves are written. Edit existing ranges by hand if you want them exact.

Does npm ci ever update the lockfile?

No. The docs say it never modifies package.json or the lockfile.

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.