| name | pnpm11-migration |
|---|---|
| description | Step-by-step guide for migrating a Podman Desktop extension from pnpm v10 to v11. Covers config relocation, workspace YAML format, Containerfile updates, CI workflow fixes, and common pitfalls. Triggers when upgrading pnpm to v11 or fixing pnpm v11 compatibility issues. |
pnpm v11 requires Node.js 22+ and moves all non-auth configuration out of
.npmrc and package.json#pnpm into pnpm-workspace.yaml using camelCase
keys.
- Node.js 22+
- Existing pnpm v10 workspace with
pnpm-workspace.yaml
pnpx codemod run pnpm-v10-to-v11 --no-interactive --allow-child-processThis handles:
- Moving
pnpm.overridesfrompackage.json→pnpm-workspace.yaml - Converting
onlyBuiltDependencies(list) →allowBuilds(boolean map) - Moving
.npmrcsettings →pnpm-workspace.yaml(camelCase keys) - Deleting
.npmrcif it only contained non-auth settings - Updating
packageManagerto the latest pnpm v11 version
The codemod writes packageManager without an integrity hash (e.g.
pnpm@11.x.y). Corepack requires the hash for verification. Get it and update
package.json:
# Get the sha512 integrity string for the installed version
PNPM_VERSION=$(node -e "console.log(require('./package.json').packageManager.split('@')[1])")
INTEGRITY=$(npm view pnpm@${PNPM_VERSION} dist.integrity)
BASE64=${INTEGRITY#sha512-}
# Convert base64 to hex
HEX=$(python3 -c "import base64, sys; print(base64.b64decode(sys.argv[1]).hex())" "$BASE64")
echo "pnpm@${PNPM_VERSION}+sha512.${HEX}"Update package.json:
{
"packageManager": "pnpm@11.x.y+sha512.<hex>"
}Activate via Corepack:
corepack enable && corepack install
pnpm --version # should print 11.xCheck all Containerfiles under build/ for the following issues.
# REMOVE this line — file no longer exists
COPY --chown=1001:root .npmrc /opt/app-root/extension-source/# REMOVE — nodeLinker is now in pnpm-workspace.yaml
RUN echo "node-linker=hoisted" >> /opt/app-root/extension/.npmrcpnpm v11 prompts for confirmation before purging node_modules when the store
format changes. Set CI=true to suppress this in non-TTY environments:
RUN CI=true pnpm install && \
pnpm buildGitHub Actions sets CI=true by default, so workflow files do not need this.
Builder images (e.g. Containerfile.builder) that explicitly install pnpm with
npm install --global pnpm@10 must be updated. Do not replace with
npm install --global pnpm@11 — use Corepack instead so the version is always
read from packageManager in package.json.
UBI / RHEL images:
registry.access.redhat.com/ubi*/nodejs-*images do not shipcorepack. Install it via npm in the root setup step before callingcorepack enable.
Before:
USER root
RUN dnf install -y jq
USER default
# ...
COPY package.json .
COPY pnpm-lock.yaml .
RUN npm install --global pnpm@10 && \
pnpm --frozen-lockfile installAfter:
USER root
RUN dnf install -y jq && npm i -g corepack && corepack enable
USER default
# ...
COPY package.json .
COPY pnpm-lock.yaml .
COPY pnpm-workspace.yaml .
RUN corepack install && \
CI=true pnpm --frozen-lockfile installcorepack install reads the packageManager field (including the sha512 hash
set in Step 2) and installs exactly that version. The corepack enable call in
the root step makes the corepack shim available system-wide so the
non-root user can invoke it.
pnpm-workspace.yaml must be copied alongside package.json and
pnpm-lock.yaml — it now holds overrides, and pnpm v11 will reject a frozen
install with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH if the file is absent.
Search all workflow files for a hardcoded pnpm version in pnpm/action-setup:
grep -rn 'version:' .github/workflows/When packageManager is set in package.json, the pnpm/action-setup action
reads the version from there automatically — remove the version: field so the
workflow stays in sync without further edits:
Before:
- uses: pnpm/action-setup@...
with:
version: 10
run_install: falseAfter:
- uses: pnpm/action-setup@...
with:
run_install: falsepnpm v11 changed how -C (change directory) resolves in workspaces — it may
return the root workspace package instead of the target. Replace with
--filter:
Before:
pnpm list -C packages/extension/ --json | jq -r '.[0].devDependencies."@podman-desktop/api".version'After:
pnpm list --filter <package-name> --json --depth 0 | jq -r '.[0].devDependencies."@podman-desktop/api".version'Where <package-name> is the name field from the target package's
package.json.
Search for all occurrences:
grep -rn 'pnpm list.*-C\|pnpm list.*--dir' .github/ build/ scripts/pnpm installThis regenerates pnpm-lock.yaml in v11 format. Review the diff — the
overrides section in the lockfile should match pnpm-workspace.yaml.
Run the full verification suite:
pnpm build
pnpm test
pnpm typecheck
podman build -t local_image -f build/Containerfile ./pnpm v11 prompts before purging node_modules when upgrading from v10's store
format. In containers and CI, set CI=true as an environment variable. Do NOT
set confirmModulesPurge: false in pnpm-workspace.yaml — that would also
suppress the prompt for developers.
pnpm v11 no longer reads npm_config_* environment variables. Rename them to
pnpm_config_* in CI configs, shell profiles, and Docker images.
The codemod writes packageManager without a sha512 hash. Corepack will not
verify the binary without it. Always complete Step 2 after running the codemod.
If a Containerfile only copies package.json and pnpm-lock.yaml, pnpm v11
will reject --frozen-lockfile with a config mismatch error because
pnpm-workspace.yaml (which now holds overrides) is missing. Always copy all
three files:
COPY package.json .
COPY pnpm-lock.yaml .
COPY pnpm-workspace.yaml .- Codemod ran without errors
-
pnpm.overridesremoved frompackage.json -
overridespresent inpnpm-workspace.yaml -
onlyBuiltDependenciesconverted toallowBuildsmap -
.npmrcsettings moved topnpm-workspace.yaml(camelCase) -
.npmrcdeleted or trimmed to auth-only -
packageManagerupdated with sha512 hash - Containerfile: no
.npmrcCOPY - Containerfile: no runtime
.npmrccreation - Containerfile:
CI=trueonpnpm install - Builder Containerfile:
npm install --global pnpm@10replaced with Corepack pattern (see Step 3) - Builder Containerfile (UBI images):
npm i -g corepack && corepack enableadded to the root setupRUNstep - Builder Containerfile:
pnpm-workspace.yamladded to COPY statements - GitHub Actions:
version:removed from allpnpm/action-setupsteps - All
pnpm list -Creplaced with--filter - No
npm_config_*env vars in CI workflows -
pnpm installsucceeds -
pnpm buildsucceeds -
pnpm testpasses - Container image builds successfully