Short answer
corepack enable (Node.js 22 and 24), npm install -g pnpm, or the script curl -fsSL https://get.pnpm.io/install.sh | sh -. Installed but not found? Run pnpm setup to put $PNPM_HOME/bin on PATH (the folder since pnpm 11), then open a new terminal.The message itself only says that the shell looked through every directory in PATH and found no program called pnpm. zsh on a Mac prints zsh: command not found: pnpm, bash prints bash: pnpm: command not found, and Debian’s sh (dash), which runs Dockerfile RUN lines and npm scripts, prints sh: 1: pnpm: not found. All three exit with status 127. Which fix you need depends on how pnpm was supposed to get there:
Where to start
- If pnpm was never installed on this machinepick one of the three install methods
- If you installed it, but zsh or bash still cannot find itput $PNPM_HOME/bin on PATH
- If pnpm add -g stops with ERR_PNPM_GLOBAL_BIN_DIR_NOT_IN_PATHrun pnpm setup, or set two variables
- If a Docker build or CI job says sh: 1: pnpm: not foundinstall pnpm in the image or job
- If pnpm says the @pnpm/exe package is not installed, or that it runs through Node.jsreinstall with scripts and optional packages on
- If Windows says 'pnpm' is not recognized as an internal or external commandfix the Windows PATH
Which install method do you have?
pnpm can reach your machine three ways, and each one puts the command in a different directory. Find out what is there before you install a second copy:
command -v node npm corepack pnpm # prints a path for each one it finds
node --version
echo "$PNPM_HOME" # empty: the standalone script never ran setup
npm prefix -g # npm puts global commands in <this>/bin
ls ~/.local/share/pnpm ~/Library/pnpm 2>/dev/null # Linux / macOS default PNPM_HOMEWhere pnpm lives
- PNPM_HOME default, Linux
- ~/.local/share/pnpm
- PNPM_HOME default, macOS
- ~/Library/pnpm
- PNPM_HOME default, Windows
- %LOCALAPPDATA%\pnpm
- With XDG_DATA_HOME set
- $XDG_DATA_HOME/pnpm
- Commands since pnpm 11
- $PNPM_HOME/binpnpm 10 and older used $PNPM_HOME itself
- npm -g install
- $(npm prefix -g)/bin
- Corepack shims
- next to the node binarycorepack enable
- Latest pnpm on npm
- 12.16.1npm registry, 2 Nov 2026
If command -v node prints nothing, Node.js is missing too. That only matters for Corepack and npm: the standalone script installs pnpm without it. When npm is the command that is missing, start with npm: command not found.
How do I fix it with Corepack?
Corepack is the Node.js project’s shim for package managers. It is bundled with Node.js 22 and 24, and corepack enable writes pnpm and pnpx links next to your node binary. The first time you run pnpm, Corepack downloads the version the project pins and caches it.
corepack enable # sudo corepack enable if node is in /usr/bin
corepack use pnpm@latest # pins it in package.json ("packageManager")
pnpm --versionNode.js 25 and later no longer ship Corepack. On a server with Node.js 26.12.1 from nvm, the bin directory held exactly three programs, node, npm and npx, and corepack --version answered bash: line 1: corepack: command not found. Install it from npm first. Corepack 0.36.0, the current release, supports Node.js 22.22.2 and later 22.x, 24.15.0 and later 24.x, and 26 or newer. Node.js 25 is out of support, so move to 24 or 26 rather than fighting it.
npm install -g corepack # sudo if node lives in /usr/bin
corepack enable
pnpm --versionCorepack runs no install scripts and installs no optional packages, which is exactly how the pnpm 12 npm package normally fetches its native binary. pnpm therefore ships a small Node.js wrapper for Corepack that downloads and checks the binary on first use. Early pnpm 12 builds did not have it and failed under Corepack with MODULE_NOT_FOUND. If you see that, pin a current version with corepack use pnpm@latest. The other Corepack errors (the download prompt, Cannot find matching keyid, This project is configured to use yarn) are covered in the yarn and Corepack guide.
How do I fix it with npm?
npm install -g pnpm@latest works on Node.js 18 and newer and is what the pnpm documentation recommends on Windows, where Defender can block the standalone executable. The command lands in $(npm prefix -g)/bin: /usr/bin with a NodeSource or distribution Node.js, ~/.nvm/versions/node/<version>/bin with nvm. Two traps:
- nvm keeps global packages per Node.js version. After
nvm use 24ornvm installof a new version, the pnpm you installed under the old one is gone from PATH. Install it again, or use Corepack in each version. - Permission errors. With Node.js in
/usr, a global install needs root. On your own serversudo npm install -g pnpmis fine; on a workstation move npm’s prefix into your home as shown in the npm EACCES fix.
How do I fix it with the standalone script?
The official script needs no Node.js. It reads the latest version from the npm registry, downloads the native binary for your platform (pnpm 12 checks it against npm’s signing key when openssl is present, and always against a SHA-512 checksum), and then runs pnpm’s built-in setup (pnpm pm setup --force on pnpm 11 and 12.1 or later), which creates PNPM_HOME and adds $PNPM_HOME/bin to the startup file of the shell named in $SHELL.
curl -fsSL https://get.pnpm.io/install.sh | sh -
# no curl:
wget -qO- https://get.pnpm.io/install.sh | sh -
# a specific version or major line:
curl -fsSL https://get.pnpm.io/install.sh | env PNPM_VERSION=11 sh -
exec $SHELL -l # or open a new terminal
pnpm --versionThe script edits the startup file, not the terminal you are typing in. The most common cause of zsh: command not found: pnpm right after a successful install is simply the old window: open a new one or run source ~/.zshrc. Run the script as your normal user. With sudo it installs into root’s home, where your account never looks, and pnpm 12 refuses sudo pnpm setup, sudo pnpm self-update and sudo pnpm add -g outright with ERR_PNPM_SUDO_NOT_SUPPORTED, because it keeps global packages in the home of the user who calls it. On a machine that matters, download it first, read it, then run it: curl -fsSL https://get.pnpm.io/install.sh -o pnpm-install.sh.
pnpm self-update updates pnpm in place (from 11.10 it can go straight to 12). In a project that pins pnpm it also rewrites the packageManager pin. Under Homebrew use brew upgrade pnpm.
Installed, but zsh or bash still says command not found?
Then the directory is not on PATH in this shell. Check what the shell actually has:
echo "$PATH" | tr ':' '\n' | grep -i pnpm
pnpm bin -g # the directory pnpm expects on PATH (needs a working pnpm)
ls "$PNPM_HOME/bin" "$PNPM_HOME" 2>/dev/nullIf PATH contains ~/.local/share/pnpm but not ~/.local/share/pnpm/bin, you have a startup block written by pnpm 10 or older. pnpm 11 moved globally installed commands into the bin subfolder so that internal folders such as global/ and store/ stay out of tab completion. Run pnpm setup once, or replace the block by hand. If the shell cannot find pnpm at all, call it by full path: $PNPM_HOME/bin/pnpm (pnpm 11+) or $PNPM_HOME/pnpm (pnpm 10). Run it outside a project folder, or as pnpm pm setup, because a project script named setup takes precedence.
export PNPM_HOME="$HOME/.local/share/pnpm" # macOS: "$HOME/Library/pnpm"
case ":$PATH:" in
*":$PNPM_HOME/bin:"*) ;;
*) export PATH="$PNPM_HOME/bin:$PATH" ;;
esacset -gx PNPM_HOME "$HOME/.local/share/pnpm"
fish_add_path "$PNPM_HOME/bin"Other reasons the block does not take effect:
- Wrong file.
pnpm setupwrites to the startup file of the shell in$SHELL. If you installed from bash and then switched to zsh (macOS uses zsh by default), the lines sit in~/.bashrcand zsh never reads them. If$SHELLis unset, setup only prints the lines for you to add. - Non-interactive shells. The stock
~/.bashrcon Debian and Ubuntu starts withcase $- in *i*) ;; *) return;; esac, so a block appended at the end never runs forssh server 'pnpm install', cron jobs or systemd units. Put the two lines above that guard, or use full paths in scripts. - sudo. sudo resets PATH, so
sudo pnpmfails even thoughpnpmworks. Project commands do not need root, and pnpm 12 rejectssudo pnpm setup,sudo pnpm self-updateandsudo pnpm add -gwithERR_PNPM_SUDO_NOT_SUPPORTEDanyway. Read-only commands such assudo pnpm bin -gstill work. - A cached lookup. After moving things around, run
hash -rin bash orrehashin zsh. - Two copies. An old JavaScript pnpm earlier on PATH can shadow a new one and break with
Cannot find module.which -a pnpmlists every copy; delete the stale one.
How do I fix ERR_PNPM_GLOBAL_BIN_DIR_NOT_IN_PATH?
This error comes from pnpm itself, so pnpm runs, but pnpm add -g or pnpm ls -g refuses to work because the folder where global commands would land is not on PATH:
ERR_PNPM_GLOBAL_BIN_DIR_NOT_IN_PATH The configured global bin directory "/home/you/.local/share/pnpm/bin" is not in PATHWhen PNPM_HOME is not set at all, pnpm 10 (and some pnpm 11 code paths) stop earlier with ERR_PNPM_NO_GLOBAL_BIN_DIR Unable to find the global bin directory; the fix is the same. The directory pnpm expects, which pnpm bin -g prints, is $PNPM_HOME/bin, or $XDG_DATA_HOME/pnpm/bin, or the per-OS default from the table above, unless you set globalBinDir yourself.
Symptom, cause, fix
Symptom: Started after upgrading from pnpm 10 to 11 or 12
- Cause
- Your startup file adds $PNPM_HOME to PATH, pnpm now wants $PNPM_HOME/bin. Globals installed under pnpm 10 stay in the old place.
- Fix
- Run
pnpm pm setup, open a new terminal, then reinstall your global tools withpnpm add -g. Note their names withpnpm ls -gbefore the upgrade if you can.
Symptom: Right after installing pnpm or running pnpm setup
- Cause
- The current shell started before the startup file changed.
- Fix
- Open a new terminal or run
source ~/.zshrc(or~/.bashrc).
Symptom: In GitHub Actions or another CI runner
- Cause
- A hand-written step written for pnpm 10 adds $PNPM_HOME instead of $PNPM_HOME/bin.
- Fix
shell step export PNPM_HOME="$HOME/.local/share/pnpm" export PATH="$PNPM_HOME/bin:$PATH" # GitHub Actions: pnpm setup also writes both to GITHUB_ENV and GITHUB_PATH
Symptom: You only wanted to run one tool once
- Cause
- A global install is not needed at all.
- Fix
- Use
pnpm dlx <package>(orpnxon pnpm 11 and later), which needs no global bin directory.
sh: 1: pnpm: not found in a Dockerfile or CI job
Inside a container, RUN pnpm install fails with /bin/sh: 1: pnpm: not found (on Alpine, whose busybox shell drops the line number: /bin/sh: pnpm: not found) because the base image has no pnpm, and RUN lines run with /bin/sh -c, which reads no ~/.bashrc. So even an image where the install script ran earlier will not see PNPM_HOME unless you set it with ENV. The official node images contain Corepack up to Node.js 24; from Node.js 26 they contain neither Corepack nor Yarn.
FROM node:24-slim
WORKDIR /app
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0
RUN corepack enable
COPY package.json pnpm-lock.yaml ./
RUN corepack install && pnpm install --frozen-lockfile
COPY . .
RUN pnpm run buildFROM node:26-slim
WORKDIR /app
RUN npm install -g pnpm@12 # lands in /usr/local/bin, already on PATH
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm run buildThe pnpm project also publishes an official image, ghcr.io/pnpm/pnpm (Debian slim, or -alpine tags), with pnpm already on PATH and no Node.js inside. Use it as the base and add Node.js with pnpm runtime set node 24 -g, or copy pnpm out of it into your own Node.js image:
FROM node:24-slim
COPY --from=ghcr.io/pnpm/pnpm:12 /opt/pnpm /opt/pnpm
RUN for bin in pnpm pn pnpx pnx; do ln -s "/opt/pnpm/$bin" "/usr/local/bin/$bin"; done
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm run buildFROM debian:13-slim
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates openssl \
&& rm -rf /var/lib/apt/lists/*
ENV PNPM_HOME=/root/.local/share/pnpm
ENV PATH="$PNPM_HOME/bin:$PATH"
# PNPM_NO_MODIFY_PATH=1 (pnpm 12.16+): install without editing any shell file
RUN curl -fsSL https://get.pnpm.io/install.sh | env PNPM_NO_MODIFY_PATH=1 sh -
RUN pnpm runtime set node 24 -g # pnpm runs without Node.js, your build scripts do not
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfileLeave out the pnpm runtime set node line and pnpm itself still works, but pnpm install of a package with build scripts, or pnpm run build, stops with node: not found. The runtime pnpm installs this way has no npm, npx or corepack.
corepack install needs the packageManager pin in package.json and fails without one. In CI the rule is the same: pnpm has to exist before the first step that calls it. In GitHub Actions the pnpm docs now use the pnpm/setup action (v3.1.2), which installs pnpm and, with runtime: node@24, Node.js too; the older pnpm/action-setup also puts pnpm on PATH. In GitLab CI or any container-based runner, use ghcr.io/pnpm/pnpm as the job image, or put the install at the top of before_script, ahead of any pnpm config set. A corepack enable step works too, but the pnpm docs advise against Corepack in CI because it runs pnpm through a Node.js shim on every call. On deploy platforms, a start command such as pnpm start that fails with /bin/bash: line 1: pnpm: command not found usually means the build never chose pnpm: commit pnpm-lock.yaml and the packageManager field so the builder can detect it.
“The @pnpm/exe package is not installed”
pnpm 12 is a native executable. The pnpm package on npm only holds placeholder commands plus preinstall and postinstall scripts, and the real binary arrives as an optional dependency such as @pnpm/exe.linux-x64, @pnpm/exe.darwin-arm64 or @pnpm/exe.win32-x64. Which message you get depends on which half was skipped:
- Optional packages skipped (
omit=optional,--no-optional): the install script fails whilenpm install -gis still running, withThe "@pnpm/exe.linux-x64" package is not installed, so pnpm has no native binary to run.(your platform in the package name). - Only the scripts skipped (
ignore-scripts=true): the placeholder stays in place. With Node.js present it hands over to its JavaScript entry and, in a terminal, warnspnpm is running through Node.js because the script that installs its native binary was skipped.pnpm works, just slower. - Scripts skipped and no Node.js: the placeholder stops with
pnpm's native binary was not installed, and there is no Node.js to run pnpm without it.
npm config get ignore-scripts # must be false
npm config get omit # must not contain optional
npm uninstall -g pnpm
npm install -g pnpm@latest --include=optionalOn a platform pnpm 12 does not build for, it says pnpm does not ship a prebuilt binary for followed by the platform. The pnpm 12 binaries cover Linux x64 and arm64 with glibc and with musl (Alpine), macOS and Windows (x64 and arm64), and since pnpm 12.4 also Linux riscv64, ppc64le and s390x, FreeBSD x64 and Android (arm64 and x64). Anywhere else, install pnpm 11 (npm install -g pnpm@11), which is JavaScript and needs Node.js 22.13 or newer.
pnpm is not recognized on Windows
'pnpm' is not recognized as an internal or external command in cmd, or The term 'pnpm' is not recognized in PowerShell, is the same missing-PATH case. Install with npm install -g pnpm@latest, which puts the command into %AppData%\npm, then open a new terminal. With the PowerShell installer (Invoke-WebRequest https://get.pnpm.io/install.ps1 -UseBasicParsing | Invoke-Expression), pnpm lives in %LOCALAPPDATA%\pnpm\bin and setup writes it to your user PATH; terminals that were already open keep the old PATH.
pnpm vs npm vs yarn: where each command comes from
| npm | pnpm | Yarn | |
|---|---|---|---|
| Ships with Node.js | Yes | No | No |
| corepack enable (Node.js 22, 24) | Not needed | Adds pnpm, pnpx | Adds yarn, yarnpkg |
| Installer that needs no Node.js | No | get.pnpm.io script | No |
| Global commands on Linux | $(npm prefix -g)/bin | ~/.local/share/pnpm/bin | Yarn 1: $(yarn global bin) |
| Run a package without installing | npx | pnpm dlx, pnx | yarn dlx (Yarn 2+) |
| Lockfile | package-lock.json | pnpm-lock.yaml | yarn.lock |
| Error when it is missing in sh | sh: 1: npm: not found | sh: 1: pnpm: not found | sh: 1: yarn: not found |
Whichever one a project uses, use only that one: its lockfile is what makes installs repeatable. If yarn is the command that is missing, or it answers with a strange There are no scenarios error, see yarn: command not found.
Building a Node.js project on a VPS is the usual place these errors show up, since a fresh server has none of your workstation’s shell setup. Our Standard KVM servers come with root access, so the system-wide routes above (sudo corepack enable, sudo npm install -g pnpm) work as shown.
A different tool missing, or a directory to add to PATH for good in bash, zsh and fish? See command not found: the three causes and the fix for every tool.
How we tested
- OS image
- Debian 12
- Versions
- Node.js 26.12.1 (nvm)npm 11.20.0bash 5.2.15dash (/bin/sh)
- Tested on
- Method
- Read-only check on a server without pnpm: the exact not-found messages from bash and sh, exit status 127, which programs a Node.js 26 install ships (node, npm, npx, no Corepack), npm's global prefix, the non-interactive guard in /etc/skel/.bashrc, and pnpm and Corepack versions and package metadata read from the npm registry.
Frequently asked
Why is pnpm not found after I installed it?
The install worked, but this shell does not have pnpm's folder on PATH. The install script and 'pnpm setup' edit the startup file of the shell in $SHELL, so open a new terminal or run 'source ~/.zshrc'. Since pnpm 11 the folder is $PNPM_HOME/bin (~/.local/share/pnpm/bin on Linux, ~/Library/pnpm/bin on macOS); an older block that adds only $PNPM_HOME is not enough.
Does Node.js include pnpm?
No. Node.js ships npm and npx (plus Corepack on 22 and 24), but not pnpm. On Node.js 22 or 24, 'corepack enable' adds pnpm. Node.js 25 and later no longer include Corepack: run 'npm install -g corepack' first, or install pnpm directly with 'npm install -g pnpm'.
How do I fix ERR_PNPM_GLOBAL_BIN_DIR_NOT_IN_PATH?
Run 'pnpm setup' (or 'pnpm pm setup' inside a project, where a 'setup' script would run instead), then open a new terminal. It adds $PNPM_HOME/bin to your shell's PATH; 'pnpm bin -g' prints the folder pnpm expects. In Docker or CI, set PNPM_HOME and add $PNPM_HOME/bin to PATH yourself. The error is common after upgrading from pnpm 10, which used $PNPM_HOME itself; reinstall your global tools afterwards.
Do I need Node.js to install pnpm?
Not with the standalone script: 'curl -fsSL https://get.pnpm.io/install.sh | sh -' installs the native pnpm 12 binary, which runs without Node.js (your project's build scripts still need Node.js; 'pnpm runtime set node 24 -g' adds it). Corepack and 'npm install -g pnpm' need Node.js, and pnpm 11 needs Node.js 22.13 or newer.
Why does my Dockerfile say sh: 1: pnpm: not found?
The base image has no pnpm, and RUN lines use /bin/sh, which reads no ~/.bashrc. On node:24 add 'RUN corepack enable'; on node:26, which has no Corepack, add 'RUN npm install -g pnpm'. With the install script, also set ENV PNPM_HOME and ENV PATH="$PNPM_HOME/bin:$PATH".