All three package managers have a strict install mode for CI: npm ci, pnpm install with the frozen lockfile option, and yarn install with the immutable option. Each refuses to change the lockfile and fails if it does not match package.json. They differ in defaults, so confirm what your CI actually runs.
The three modes side by side
| npm | pnpm | Yarn | |
|---|---|---|---|
| Command | npm ci | pnpm install with frozen lockfile | yarn install with immutable |
| Fails if lockfile and manifest disagree | Yes | Yes | Yes, if the lockfile would be modified |
| Needs a lockfile | Yes | Yes, in CI | Yes |
| Default in CI | It is the command itself | True in CI when a lockfile is present | True on CI |
| Also does | Deletes node_modules first | Skips staleness checks only with other options | Immutable cache and check cache options exist |
What the docs say
For npm, the documentation says npm ci is a clean install for automated environments. It requires an existing package-lock.json or npm-shrinkwrap.json, deletes any existing node_modules, never modifies package.json or lock files, and exits with an error if the lock file does not match package.json. It cannot add individual dependencies.
For pnpm, the install reference says frozen lockfile makes pnpm fail if the lockfile is out of sync with the manifest. It is true in CI when a lockfile is present, with CI detected from environment variables such as CI and BUILD_NUMBER.
For Yarn, the install reference says immutable aborts with an error if the lockfile would be modified, and defaults to true on CI. Separate options cover the cache folder, and check cache refetches every package and verifies checksums.
Why this matters for security
A lockfile only protects you if the build uses it. A plain install can quietly rewrite the lockfile, resolve a newer version, and ship something nobody reviewed. A strict mode turns that into a failed build, which is the safe failure.
Extra care for npm: if the lockfile was created with flags that change the tree, such as legacy peer dependencies, the docs say to pass the same flags to npm ci, ideally stored in a committed npmrc file.
Steps
- Pick the strict command for your package manager and put it in your CI config explicitly, even if it is the default.
- Fail the build on any lockfile change, and require lockfile updates to arrive in their own reviewed commit.
- Review the lockfile diff, looking at new packages and changed sources.
- Keep install steps separate from steps that run your own code, so a failed install stops early.
For the npm specifics see npm ci vs npm install for supply chain safety.
Try it yourself
Click through it at your own pace, or open it full screen.
Watch a pull request fail a policy check. A mismatched lockfile is the kind of thing a gate should catch.
Quick check
Does npm ci ever update the lockfile?
No. It never modifies package.json or lock files, and fails if they do not match.
Is the frozen lockfile option on by default in pnpm CI?
Yes, according to the pnpm docs it is true in CI when a lockfile is present.
Safeguard gates can review dependency changes in pull requests, and the free scan at gold.safeguard.sh/scan inventories what your lockfile resolves.
Sources
Last reviewed: 19 October 2026.