Files
Alessio AttilioandZoltan Kochan 6175c327eb fix(install): relink changed workspace bins on repeat installs (#17325)
Record a digest of every workspace package's bin declarations in the
repeat-install state so a changed `bin` field relinks the current bins
on the next install, even with --frozen-lockfile and an unchanged
lockfile.

The state used to record each project's name and version but not its
bins, so the frozen-tree gate, the optimistic freshness check, and the
dependency-status check all read a workspace whose only change was a
bin declaration as up to date. The digest covers the whole workspace
and is recorded under the importer id of every project that links
workspace bins (the root and every project with dependencies). A
coarse digest keeps the check independent of the dependency graph; it
changes only when a declaration changes, at the cost of one extra
install for a filtered project whose own bins did not move.

A filtered install vouches only for the projects it installs and
carries the previous records for the others, so a later install that
covers them still relinks. A state without a validation record proves
nothing about any project and defers to the existing timestamp
fallback instead of reading as a mismatch, which would otherwise put
every workspace with bins on the slow path on every run. The
held-projects check returns before hashing the workspace when nothing
is held.

Both CLIs hash the declarations the same way, pinned by paired unit
tests, with e2e coverage for the isolated and hoisted linkers in each.
Removing shims of bins no longer declared is pre-existing behavior on
both CLIs, including with --force, and is tracked in
https://github.com/pnpm/tasks/issues/211.

Closes pnpm/pnpm#17324.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-10-25 15:23:45 +01:00

8.0 KiB

id, title
id title
install pnpm install

Aliases: i

pnpm install is used to install all dependencies for a project.

Large package downloads use temporary disk space to keep memory usage bounded. Temporary download files are removed after extraction or a failed download. Package manifests and archive metadata that need buffering are limited to 64 MiB.

In a CI environment, installation fails if a lockfile is present but needs an update. To allow lockfile updates in CI, run pnpm install --no-frozen-lockfile.

Inside a workspace, pnpm install installs all dependencies in all the projects. If you want to disable this behavior, set the recursiveInstall setting to false.

Changes to a workspace package's bin field are linked into its dependents' node_modules/.bin on the next install, even with --frozen-lockfile and an unchanged lockfile.

TL;DR

Command Meaning
pnpm i --offline Install offline from the store only
pnpm i --frozen-lockfile pnpm-lock.yaml is not updated
pnpm i --lockfile-only Only pnpm-lock.yaml is updated
pnpm i --dry-run Preview changes without writing

Options for filtering dependencies

Without a lockfile, pnpm has to create one, and it must be consistent regardless of dependencies filtering, so running pnpm install --prod on a directory without a lockfile would still resolve the dev dependencies, and it would error if the resolution is unsuccessful. The only exception for this rule are link: dependencies.

Without --frozen-lockfile, pnpm will check for outdated information from file: dependencies, so running pnpm install --prod without --frozen-lockfile on an environment where the target of file: has been removed would error.

--prod, -P

  • Default: false
  • Type: Boolean

If true, pnpm will not install any package listed in devDependencies and will remove those insofar they were already installed. If false, pnpm will install all packages listed in devDependencies and dependencies.

--dev, -D

Only devDependencies are installed and dependencies are removed insofar they were already installed.

--no-optional

optionalDependencies are not installed.

--no-runtime

Added in: v11.1.0

Skip installing runtime entries (e.g. Node.js downloaded via devEngines.runtime). The lockfile is left untouched, so frozen installs still validate; only the runtime fetch and bin-linking are skipped.

This is useful in CI matrices where the runtime is provisioned externally (e.g. via pnpm runtime -g set node <version>) before pnpm install runs.

This can also be set with runtime: false in pnpm-workspace.yaml.

Options

--force

Force reinstall dependencies: refetch packages modified in store, recreate a lockfile and/or modules directory created by a non-compatible version of pnpm. Install all optionalDependencies even they don't satisfy the current environment(cpu, os, arch).

Since v11.28.0, set forceIgnoresPlatform to false to keep skipping optional dependencies whose os, cpu, or libc do not match the host under --force.

--offline

  • Default: false
  • Type: Boolean

If true, pnpm will use only packages already available in the store. If a package won't be found locally, the installation will fail.

--prefer-offline

  • Default: false
  • Type: Boolean

If true, staleness checks for cached data will be bypassed, but missing data will be requested from the server. To force full offline mode, use --offline.

--no-lockfile

Don't read or generate a pnpm-lock.yaml file.

--lockfile-only

  • Default: false
  • Type: Boolean

When used, only updates pnpm-lock.yaml and package.json. Nothing gets written to the node_modules directory.

--dry-run

Added in: v11.8.0

Run a full dependency resolution and report what a real install would change, without writing anything to disk. No lockfile, manifest, or node_modules changes are saved.

A completed dry run exits with code 0, even when it reports that a real install would update the lockfile.

--dry-run cannot be used with a configured pnpr server, because that install path resolves and links through the server.

--fix-lockfile

Fix broken lockfile entries automatically.

--update-checksums

Added in: v11.4.0

Refresh the locked tarball integrity values from what the registry currently serves, when a downloaded tarball's hash doesn't match the integrity recorded in pnpm-lock.yaml.

By default, since v11.4.0, an integrity mismatch is a hard failure: pnpm install exits with ERR_PNPM_TARBALL_INTEGRITY rather than silently re-resolving from the registry and overwriting the locked integrity. This protects projects that ship a committed lockfile from a compromised registry, proxy, or republished version substituting attacker-controlled content on a clean machine.

--update-checksums is the narrowly-scoped opt-in for the legitimate case (e.g. a registry rewrote its tarballs and you've verified the new bytes are correct). A warning still prints when the bypass takes effect so the operation is auditable.

--force and pnpm update deliberately do not bypass the integrity check. --frozen-lockfile is unchanged, and --fix-lockfile keeps its documented purpose (filling in missing lockfile entries) and is also not a bypass.

--frozen-lockfile

  • Default:
    • For non-CI: false
    • For CI: true, if a lockfile is present
  • Type: Boolean

If true, pnpm doesn't generate a lockfile and fails to install if the lockfile is out of sync with the manifest / an update is needed or no lockfile is present.

This setting is true by default in CI environments. pnpm detects a CI environment with the ci-info package. Set CI=false to turn detection off.

--no-frozen-lockfile

Allows lockfile updates during installation. This is the inverse of --frozen-lockfile.

--merge-git-branch-lockfiles

Merge all git branch lockfiles. Read more about git branch lockfiles.

--reporter=<name>

  • Default:
    • For TTY stdout: default
    • For non-TTY stdout: append-only
  • Type: default, append-only, ndjson, silent

Allows you to choose the reporter that will log debug info to the terminal about the installation progress.

  • silent - no output is logged to the console, not even fatal errors
  • default - the default reporter when the stdout is TTY
  • append-only - the output is always appended to the end. No cursor manipulations are performed
  • ndjson - the most verbose reporter. Prints all logs in ndjson format

If you want to change what type of information is printed, use the loglevel setting.

--shamefully-hoist

  • Default: false
  • Type: Boolean

Creates a flat node_modules structure, similar to that of npm or yarn. WARNING: This is highly discouraged.

--ignore-scripts

  • Default: false
  • Type: Boolean

Do not execute any scripts defined in the project package.json and its dependencies.

--filter <package_selector>

Read more about filtering.

--resolution-only

Re-runs resolution: useful for printing out peer dependency issues.

:::info

To list peer dependency issues without re-running resolution, use pnpm peers check. It reads them from the lockfile.

:::

import CpuFlag from '../settings/_cpuFlag.mdx'

import OsFlag from '../settings/_osFlag.mdx'

import LibcFlag from '../settings/_libcFlag.mdx'