pnpm add <pkg>
Installs a package and any packages that it depends on. By default, any new package is installed as a production dependency.
TL;DR#
| Command | Meaning |
|---|---|
pnpm add sax | Save to dependencies |
pnpm add -D sax | Save to devDependencies |
pnpm add -O sax | Save to optionalDependencies |
pnpm add -g sax | Install package globally |
pnpm add sax@next | Install from the next tag |
pnpm add sax@3.0.0 | Specify version 3.0.0 |
pnpm add lodash@npm:awesome-lodash | Install awesome-lodash as lodash |
pnpm add crate:serde | Add a Cargo crate |
pnpm add pypi:httpx | Add a Python package |
Supported package sources#
pnpm supports installing packages from various sources. See the Supported package sources page for detailed documentation on:
- npm registry
- JSR registry
- Workspace packages
- Local file system (tarballs and directories)
- Remote tarballs
- Git repositories (with semver, subdirectories, and more)
- crates.io and PyPI, through the
crate:andpypi:prefixes
Package aliases#
To install an npm package under a different local name, use an npm: alias:
pnpm add <alias>@npm:<package>
pnpm add <alias>@npm:<package>@<version-or-tag>
The package after npm: may be scoped and versioned. For example:
pnpm add babel-core@npm:@babel/core@8.0.6
This writes babel-core as the dependency name while resolving
@babel/core@8.0.6 as the target package. The npm: part is the npm
package-alias protocol, not a named registry;
registry routing still follows the target package's default or scope-specific
npm registry configuration.
See Aliases for more examples.
Adding a package manager or a runtime#
Added in: v12.0.0-rc.6 (pnpm v12 only)
Naming a package manager — npm, yarn or bun — records which one the project uses instead of installing the npm package that shares the name:
pnpm add yarn@4
writes "packageManager": "yarn@4.18.0", and every other package manager is recorded as a range in devEngines.packageManager. Naming a runtime (node, deno) records it under engines.runtime, as the explicit node@tool:22 spelling does since v12.13.0. bun is both, and is declared as the project's package manager unless you ask for the runtime (pnpm add bun@tool:1.3.0).
Globally, pnpm add -g yarn installs the current Yarn line rather than the Classic-only yarn package, and pnpm add -g node@22 installs that Node.js release rather than a wrapper that downloads one.
A specifier that locates a package rather than asking for a released version — pnpm add yarn@npm:yarn@1.22.22, pnpm add yarn@yarnpkg/berry — installs what it names, as an ordinary dependency.
Adding the Rust toolchain#
Added in: v12.11.0
rust names the Rust toolchain, not the npm package of that name. The version is a Rust release channel: a version (1.95.0 or 1.95), stable, beta, nightly, or a dated channel such as nightly-2026-01-01. A bare rust asks for stable.
In a project, pnpm add rust@1.95 pins the toolchain in the rust-toolchain.toml that governs the project, the nearest one at or above it in the workspace. It creates one in the project if there is none, and changes only the channel, keeping the rest of the file. With cargo.enabled, the toolchain is installed too. Nothing is added to package.json.
pnpm add -g rust@stable installs the toolchain globally. The cargo, rustc, and other Rust commands run it outside projects whose rust-toolchain.toml names a toolchain of their own. pnpm update -g rust installs the newest release of its channel, pnpm ls -g lists it, and pnpm remove -g rust removes it.
Protocol-prefixed selectors#
A selector may carry the protocol in front of the name rather than after it:
pnpm add jsr:@scope/pkg
pnpm add npm:pkg@^1.0.0
pnpm add workspace:pkg@*
Package URLs#
Added in: v12.5.0
pnpm add accepts Package URLs for npm, Cargo, and Python packages:
pnpm add pkg:npm/express@4.18.2
pnpm add pkg:cargo/serde@1.0.188
pnpm add pkg:pypi/requests@2.31.0
These save dependencies to package.json, Cargo.toml, and pyproject.toml, respectively. Cargo and Python use their ecosystem configuration. pkg is a reserved specifier prefix, regardless of case, and cannot be used as a named registry alias.
Options#
--save-prod, -P, -p#
Install the specified packages as regular dependencies.
--save-dev, -D, -d#
Install the specified packages as devDependencies.
--save-optional, -O, -o#
Install the specified packages as optionalDependencies.
--save-exact, -E, -e#
Saved dependencies will be configured with an exact version rather than using pnpm's default semver range operator.
--save-peer#
Using --save-peer will add one or more packages to peerDependencies and
install them as dev dependencies.
--save-types#
Added in: v12.6.0
Saves available @types/* packages in devDependencies alongside registry
dependencies. Packages that declare bundled TypeScript types are skipped.
pnpm add express --save-types
# saves express to dependencies, @types/express to devDependencies
Set saveTypes: true in pnpm-workspace.yaml to enable this by default.
--tilde#
Added in: v12.6.0
Alias for --save-prefix=~. Saved dependencies will be configured with a tilde
range (~1.2.3) instead of the default caret range (^1.2.3).
--save-catalog#
Added in: v10.12.1
Save the new dependency to the default catalog.
--save-catalog-name <catalog_name>#
Added in: v10.12.1
Save the new dependency to the specified catalog.
--config#
Added in: v10.8.0
Save the dependency to configDependencies.
Since v12.12.0, the saved range follows the same rules as for a dependency in package.json.
--ignore-workspace-root-check#
Adding a new dependency to the root workspace package fails, unless the
--ignore-workspace-root-check or -w flag is used.
For instance, pnpm add debug -w.
--global, -g#
Install a package globally. See Global Packages for details.
Each space-separated package is installed into its own isolated directory. To bundle several packages into a single isolated install (so they share dependencies and are removed together), pass them as a comma-separated list, e.g. pnpm add -g eslint,prettier.
--workspace#
Only adds the new dependency if it is found in the workspace. The dependency is
saved with the workspace: protocol
and linked from the workspace project that provides it. When no workspace
project provides the package, the command fails instead of falling back to the
registry.
--allow-build#
Added in: v10.4.0
A list of package names that are allowed to run postinstall scripts during installation.
Example:
pnpm --allow-build=esbuild add my-bundler
This will run esbuild's postinstall script and also add it to the allowBuilds field of pnpm-workspace.yaml. So, esbuild will always be allowed to run its scripts in the future.
Since v12.4.0, prefixing a name with ! denies the build instead:
pnpm add --allow-build=!core-js my-bundler
writes allowBuilds: { core-js: false }, so the package is never asked about again. Global installs (pnpm add -g) record the denial too.
--registry#
Specify the registry to use for this installation:
pnpm add --registry=https://registry.npmjs.org/ lodash
--filter <package_selector>#
--cpu=<name>#
Added in: v10.14.0
Override CPU architecture of native modules to install. Acceptable values are same as cpu field of package.json, which comes from process.arch.
--os=<name>#
Added in: v10.14.0
Override OS of native modules to install. Acceptable values are same as os field of package.json, which comes from process.platform.
--libc=<name>#
Added in: v10.14.0
Override libc of native modules to install. Acceptable values are same as libc field of package.json.