Files
dd8a695bde fix(docker): link the pn, pnpx, and pnx aliases in the image (#17282)
docker/install-pnpm.sh linked only `pnpm` into /usr/local/bin, so the
image had no `pn`, `pnpx`, or `pnx`. The script now hardlinks the
binary as each alias in /opt/pnpm and symlinks them onto PATH, as the
npm package and self-update do for the native binary. Both the v12
binary and the v11 executable read the launch name from the hardlink
and run `pnpm dlx` for `pnpx` and `pnx`. The docs recipe for copying
/opt/pnpm into another image links the aliases too. The install
script fails the build if `pn` does not print the installed version or
`pnpx` and `pnx` do not run `pnpm dlx`.

Fixes pnpm/pnpm#17275

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 00:32:19 +02:00
..

pnpm base Docker image

Official base image for pnpm, published to GitHub Container Registry.

ghcr.io/pnpm/pnpm

Based on debian:stable-slim with the pnpm standalone binary. Node.js is not bundled — install the version you need inside your own image with pnpm runtime set node <version> -g (the -g flag makes node available on PATH for subsequent layers and at runtime).

Tags

Tag Meaning
<version> Exact, immutable (e.g. 11.0.0). Includes prereleases.
<major> Tracks the latest stable release within that major (e.g. 11).
latest Highest stable pnpm version. Not updated for prereleases.
<version>-alpine, <major>-alpine, alpine The same, based on Alpine Linux with the musl build of pnpm.

Alpine variant

The -alpine tags are based on alpine:3.24 and contain the musl build of pnpm in /opt/pnpm. They are published for pnpm 12 and later.

To add pnpm to an existing image, such as node:<version>-alpine, copy the whole directory. The dist directory next to the binary holds the bundled node-gyp:

FROM node:24-alpine
COPY --from=ghcr.io/pnpm/pnpm:12-alpine /opt/pnpm /opt/pnpm
RUN for bin in pnpm pn pnpx pnx; do ln -s "/opt/pnpm/$bin" "/usr/local/bin/$bin"; done

Supported platforms

linux/amd64, linux/arm64.

Usage

Install Node.js explicitly with pnpm runtime set:

FROM ghcr.io/pnpm/pnpm:latest
RUN pnpm runtime set node 22 -g
WORKDIR /app
COPY . .
RUN pnpm install --frozen-lockfile
CMD ["node", "index.js"]

Or let pnpm install Node.js from devEngines.runtime in your package.json:

{
  "devEngines": {
    "runtime": {
      "name": "node",
      "version": "22.x",
      "onFail": "download"
    }
  }
}
FROM ghcr.io/pnpm/pnpm:latest
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
CMD ["pnpm", "start"]

Build locally

VERSION=11.0.0-rc.2
SHA=$(curl -fsSL "https://github.com/pnpm/pnpm/releases/download/v${VERSION}/pnpm-linux-x64.tar.gz" \
      | sha256sum | awk '{print $1}')
docker buildx build \
  --build-arg PNPM_VERSION=${VERSION} \
  --build-arg PNPM_SHA256_AMD64=${SHA} \
  --platform linux/amd64 \
  --load \
  -t pnpm-test ./docker
docker run --rm pnpm-test pnpm --version

For the Alpine image, checksum pnpm-linux-x64-musl.tar.gz instead and pass -f docker/Dockerfile.alpine.

Release

Images are built and pushed by .github/workflows/docker.yml on release: published, or manually via workflow_dispatch. The build fails if pnpm --version in the image doesn't match the PNPM_VERSION build-arg.