
4 Pitfalls I Hit Upgrading pnpm v10 to v11 — A Summary of Fixes for Docker and CI Environments
This page has been translated by machine translation. View original
Introduction
pnpm v11 was released, and I upgraded my project's package manager from v10. The local environment went relatively smoothly, but the Docker build and CI pipeline broke spectacularly.
In this article, I'll share the pitfalls I actually encountered and how to deal with them in a "hands-on" format. Honestly, pnpm v11 has quite a few breaking changes, and even after reading the official documentation, there are several traps that are easy to miss.
Prerequisites & Environment
- pnpm: v10.32.1 → v11 (latest)
- Node.js: 24 (LTS)
- Framework: Next.js 16
- Docker: node:24-slim base image
- CI: GitHub Actions
Major Breaking Changes in pnpm v11
Here's a summary of the key changes you should know before upgrading.
1. postinstall scripts are blocked by default
This was the biggest trap. Up through v10, postinstall scripts (such as building native modules) were executed with a warning, but in v11 they result in an error unless explicitly permitted.
ERR_PNPM_IGNORED_BUILDS The following dependencies have build scripts that are not executed: sharp, unrs-resolver
2. The location of configuration files has changed
pnpm-specific settings written in .npmrc (such as hoist-pattern, node-linker, save-exact, etc.) are not read in v11. They need to be migrated to pnpm-workspace.yaml.
| Setting type | v10 | v11 |
|---|---|---|
| Registry & authentication | .npmrc |
.npmrc (no change) |
| pnpm-specific settings | .npmrc |
pnpm-workspace.yaml |
package.json#pnpm |
Read | Ignored |
3. Environment variable prefix has changed
npm_config_* → changed to pnpm_config_*. Requires fixes in CI environments or Dockerfiles using npm_config_*.
4. Node.js 22 or higher is required
Support for Node.js 18–21 has been dropped.
4 Pitfalls I Actually Fell Into
Pitfall 1: Allowing postinstall scripts with allowBuilds
When running pnpm install, errors occur for packages requiring native builds such as sharp (image processing) and unrs-resolver (for ESLint).
Solution: Add allowBuilds to pnpm-workspace.yaml.
# frontend/pnpm-workspace.yaml
allowBuilds:
sharp: true
unrs-resolver: true
It was also needed at the project root for other packages:
# pnpm-workspace.yaml (root)
allowBuilds:
cpu-features: true
ssh2: true
Key point: You can tell which packages are affected by looking at the error messages from pnpm install. Just add the package names shown in the errors to allowBuilds and you're done.
onlyBuiltDependencies / neverBuiltDependencies / ignoredBuiltDependencies from v10 and earlier are deprecated, so if you're already using these, you'll need to rewrite them as allowBuilds.
Pitfall 2: Forgetting to COPY pnpm-workspace.yaml in the Dockerfile
pnpm-workspace.yaml has become a required configuration file in v11. However, the existing Dockerfile only COPYed package.json and pnpm-lock.yaml.
Before (broken):
COPY frontend/package.json frontend/pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
After (working):
COPY frontend/package.json frontend/pnpm-lock.yaml frontend/pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile
Without pnpm-workspace.yaml, the allowBuilds configuration isn't loaded, postinstall scripts get blocked, and the Docker build fails.
Pitfall 3: ENV CI=true is required inside Docker
Even after fixing the two issues above, pnpm install inside Docker was still failing in some cases.
The cause was that when pnpm v11 detects an unauthorized postinstall script, it interactively prompts whether to allow it. Since there's no TTY during a Docker build, this prompt either hangs or errors out.
Solution: Setting ENV CI=true puts pnpm into non-interactive mode, so it behaves according to the allowBuilds configuration without showing any prompts.
FROM node:24-slim
ENV CI=true
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
COPY frontend/package.json frontend/pnpm-lock.yaml frontend/pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile
It's just one line of ENV CI=true, but without it, the Docker build silently stops, which made it time-consuming to identify the cause.
Pitfall 4: verifyDepsBeforeRun breaks pnpm run in offline environments
In pnpm v11, verifyDepsBeforeRun is set to install by default. This is a feature that checks the state of dependencies every time pnpm run is executed and automatically runs pnpm install if there's an inconsistency.
While this seems convenient, in VPN-connected or restricted network environments, registry fetches fail and produce errors like:
TypeError: fetch failed
at Object.processResponse (...)
[ERROR] Command failed with exit code 1: ... pnpm.mjs install
Even if node_modules is fully populated, network access occurs during the automatic check → automatic install process, meaning even pnpm run cannot be executed in offline environments or behind a firewall.
Solution: Disable verifyDepsBeforeRun in pnpm-workspace.yaml.
verifyDepsBeforeRun: false
allowBuilds:
cpu-features: true
ssh2: true
Note: Writing verify-deps-before-run=false in .npmrc does not work. In pnpm v11, this setting is only read from pnpm-workspace.yaml. The environment variable PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false works, but setting it inside a script definition in pnpm run is too late (the check runs before pnpm executes the script).
If you don't want to disable it entirely, setting it to warn will perform the check but only show a warning without automatically installing:
verifyDepsBeforeRun: warn
CI (GitHub Actions) Fixes
In GitHub Actions, the version specification for pnpm/action-setup also needed to be updated.
# Before
- uses: pnpm/action-setup@v4
with:
version: 10
# After
- uses: pnpm/action-setup@v4
with:
version: latest
Since CI=true is set by default in GitHub Actions environments, no additional workarounds like those needed inside Docker were required. However, if pnpm-workspace.yaml is not properly committed to the repository, the same ERR_PNPM_IGNORED_BUILDS error will appear in CI as well.
Honest Impressions
Upgrading to pnpm v11 was, frankly speaking, a pain.
The good:
- Explicit permission for postinstall scripts via
allowBuildsis the right direction from a security standpoint as a defense against supply chain attacks - The default enabling of
minimumReleaseAge(not resolving packages published within the last 24 hours) is similarly a good decision - Having configuration centralized in
pnpm-workspace.yamlis clearer in the long run
The painful:
- The "warning → error" change is the most impactful breaking change for users, and it's especially likely to be noticed for the first time in non-interactive environments like CI/Docker
- The need to COPY
pnpm-workspace.yamlin Dockerfiles should have been written more prominently in the official documentation's Docker guide - The requirement for
ENV CI=truewas not documented anywhere and could only be discovered through trial and error - The
verifyDepsBeforeRun=installdefault causespnpm runto suddenly break in offline or VPN environments. Moreover, since configuration via.npmrcis ignored, it takes time to identify the cause - There are too many breaking changes, making it difficult to grasp everything at once even after reading the official migration guide
Ultimately, pnpm v11 represents a major shift toward a security-first design philosophy. Changes like the default denial for allowBuilds, minimumReleaseAge, and blockExoticSubdeps all lean toward the "safe side." I think the direction is right, but the migration cost is considerable.
Upgrade Steps Summary
- Run
pnpx codemod run pnpm-v10-to-v11to perform mechanical configuration migration - Run
pnpm installto identify package names appearing inERR_PNPM_IGNORED_BUILDSerrors - Add
allowBuildstopnpm-workspace.yaml - Add a COPY of
pnpm-workspace.yamlto the Dockerfile - Add
ENV CI=trueto the Dockerfile - Update the pnpm version in CI configuration (GitHub Actions, etc.)
- Migrate pnpm-specific settings from
.npmrctopnpm-workspace.yaml - Set
verifyDepsBeforeRuntofalseorwarnin offline/restricted network environments - Regenerate the lockfile (automatically updated by
pnpm install)