/flags/pnpm/pnpm-install-frozen-lockfile
pnpm install --frozen-lockfile: never update pnpm-lock.yaml (CI default)
- tool
- pnpm
- command
- pnpm install
- flag
- --frozen-lockfile, --no-frozen-lockfile, --prefer-frozen-lockfile
- default
- true in CI environments, false otherwise
pnpm install --frozen-lockfile installs exactly what pnpm-lock.yaml describes and fails if the lockfile is missing or does not match package.json, instead of updating it. pnpm turns it on automatically when it detects CI (the CI environment variable), which is why a forgotten lockfile change shows up only in the pipeline. --no-frozen-lockfile turns it off.
Local install, CI install and the flag
package.json asks for a version that the lockfile does not contain:
cat > package.json <<'EOF'
{ "name": "demo", "version": "1.0.0", "dependencies": { "is-number": "7.0.0" } }
EOF
npx --yes pnpm@9 install >/dev/null 2>&1
sed -i 's/"7.0.0"/"6.0.0"/' package.json
echo "--- --frozen-lockfile"
npx --yes pnpm@9 install --frozen-lockfile 2>&1 | grep -o "ERR_PNPM_[A-Z_]*.*up to date"
echo "--- CI=true (frozen by default)"
CI=true npx --yes pnpm@9 install 2>&1 | grep -o "ERR_PNPM_[A-Z_]*.*up to date"
echo "--- plain install updates the lockfile"
npx --yes pnpm@9 install >/dev/null 2>&1; echo "exit: $?"
grep -A1 "is-number:" pnpm-lock.yaml | head -2
npx --yes pnpm@9 install --frozen-lockfile >/dev/null 2>&1; echo "frozen again, exit: $?"Output
--- --frozen-lockfile
ERR_PNPM_OUTDATED_LOCKFILE Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date
--- CI=true (frozen by default)
ERR_PNPM_OUTDATED_LOCKFILE Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date
--- plain install updates the lockfile
exit: 0
is-number:
specifier: 6.0.0
frozen again, exit: 0The same error appears with the flag and with CI=true. After a normal install the lockfile records the new version and the frozen install succeeds. The error itself is explained, with every cause, in ERR_PNPM_OUTDATED_LOCKFILE.
Related lockfile options
| Option | Behaviour |
|---|---|
| --frozen-lockfile | Never write pnpm-lock.yaml; fail when it is absent or outdated |
| --no-frozen-lockfile | Allow updates even in CI |
| --prefer-frozen-lockfile | Use the lockfile as-is when it satisfies package.json, otherwise resolve again (the local default) |
| --fix-lockfile | Repair broken entries in the lockfile without resolving everything again |
| --lockfile-only | Update pnpm-lock.yaml without touching node_modules |
| frozen-lockfile=true in .npmrc | Make frozen installs the default everywhere |
A missing lockfile is a separate error with the same root idea: ERR_PNPM_NO_LOCKFILE.
GitHub Actions
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfileThe flag is redundant in GitHub Actions, where CI is already set, but writing it makes the intent visible and keeps the behaviour on CI systems that pnpm does not detect.
Pitfalls
- Different pnpm major versions write different lockfile formats. If CI uses another major version than developers, the lockfile looks outdated; pin pnpm with the
packageManagerfield inpackage.json. - Changing
pnpm.overrides, patched dependencies or workspace settings also invalidates the lockfile, not onlydependencies. --frozen-lockfiledoes not check that installed packages are up to date on the registry; it only enforces what was committed.
Yarn, Bun and Deno have the same safety switch: see yarn install --frozen-lockfile and deno install --frozen.
FAQ
Why does pnpm install fail in CI but work on my machine?
In CI, frozen-lockfile is on by default, so pnpm refuses to change pnpm-lock.yaml and reports ERR_PNPM_OUTDATED_LOCKFILE. Locally it is off and pnpm silently updates the lockfile. Run pnpm install locally and commit pnpm-lock.yaml.
How do I turn off frozen-lockfile in CI?
Pass --no-frozen-lockfile. It is rarely the right fix: the build then resolves versions that were never committed. Use it only for jobs that are meant to update the lockfile, such as a dependency update bot.
What is the difference between --frozen-lockfile and npm ci?
Both refuse to change the lockfile. npm ci also deletes node_modules first; pnpm keeps node_modules and only links what is missing, which is why it is faster on warm CI caches.