{"id":25621793,"url":"https://github.com/jeremy-code/gh-actions-pnpm","last_synced_at":"2026-06-24T05:31:17.528Z","repository":{"id":277781345,"uuid":"933473715","full_name":"jeremy-code/gh-actions-pnpm","owner":"jeremy-code","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-22T03:37:00.000Z","size":11,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-19T16:56:22.605Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jeremy-code.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-16T03:22:14.000Z","updated_at":"2025-02-22T03:37:04.000Z","dependencies_parsed_at":"2025-02-16T04:31:41.726Z","dependency_job_id":null,"html_url":"https://github.com/jeremy-code/gh-actions-pnpm","commit_stats":null,"previous_names":["jeremy-code/gh-actions-pnpm"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jeremy-code/gh-actions-pnpm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeremy-code%2Fgh-actions-pnpm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeremy-code%2Fgh-actions-pnpm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeremy-code%2Fgh-actions-pnpm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeremy-code%2Fgh-actions-pnpm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeremy-code","download_url":"https://codeload.github.com/jeremy-code/gh-actions-pnpm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeremy-code%2Fgh-actions-pnpm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34719097,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-22T09:49:36.115Z","updated_at":"2026-06-24T05:31:17.504Z","avatar_url":"https://github.com/jeremy-code.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gh-actions-node-corepack\n\nThis is an example of a typical Github Actions `.yml` file for a Node.js project using pnpm and corepack.\n\n```yml\nname: CI\n\non:\n  push:\n    branches: [\"main\"]\n\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node: [23.8.0]\n    steps:\n      - name: Check out Git repository\n        id: checkout\n        uses: actions/checkout@v4\n\n      - name: Enable Node.js corepack shims\n        run: |\n          npm install -g corepack\n          corepack enable\n\n      - name: Set up Node.js environment\n        id: setup_node\n        uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node }}\n          cache: pnpm\n\n      - name: Install dependencies and build\n        run: |\n          pnpm install\n          pnpm run build\n```\n\nIn general, you'll find this action works fine for most projects. However, there are some nuances involved that may be worth considering.\n\n## Context\n\nIf you are running Github Actions on Github-hosted runners, there are a set of pre-installed software. Of particular note for [`ubuntu-latest`](https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md) and [`macos-latest`](https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md) are:\n\n- Node.js `20.18.2` (Ubuntu 24.04), Node.js `20.18.1` (macOS 14)\n- NPM `10.8.2`\n- Yarn `1.22.22`\n\nThat's why running `corepack enable` before `actions/setup-node` is possible -- you are actually running `corepack` from the pre-installed Node.js version.\n\n## Caveats\n\nHowever, that does introduce an interesting dilemma. Consider:\n\n```yml\njobs:\n  *:\n    steps:\n      - name: Enable Node.js corepack shims\n        run: |\n          npm install -g corepack\n          corepack enable\n\n      - run: |\n          echo \"Node.js version: $(node -v), Node.js path: $(which node)\"\n          echo \"NPM version: $(npm -v), NPM path: $(which npm)\"\n          echo \"Corepack version: $(corepack -v), NPM path: $(which corepack)\"\n          echo \"PNPM version: $(pnpm -v), PNPM path: $(which pnpm)\"\n          echo \"Current \\$PATH: $PATH\"\n\n      - uses: actions/setup-node@v4\n\n      - run: |\n          echo \"Node.js version: $(node -v), Node.js path: $(which node)\"\n          echo \"NPM version: $(npm -v), NPM path: $(which npm)\"\n          echo \"Corepack version: $(corepack -v), Corepack path: $(which corepack)\"\n          echo \"PNPM version: $(pnpm -v), PNPM path: $(which pnpm)\"\n          echo \"Current \\$PATH: $PATH\"\n```\n\nThis is the output:\n\n```\nNode.js version: v20.18.2, Node.js path: /usr/local/bin/node\nNPM version: 10.8.2, NPM path: /usr/local/bin/npm\nCorepack version: 0.31.0, Corepack path: /usr/local/bin/corepack\nPNPM version: 10.4.0, PNPM path: /usr/local/bin/pnpm\nCurrent $PATH: /snap/bin:/home/runner/.local/bin:/opt/pipx_bin:/home/runner/.cargo/bin:/home/runner/.config/composer/vendor/bin:/usr/local/.ghcup/bin:/home/runner/.dotnet/tools:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin\n\n\u003e Setup Node.js environment\n...\n\nNode.js version: v23.8.0, Node.js path: /opt/hostedtoolcache/node/23.8.0/x64/bin/node\nNPM version: 10.9.2, NPM path: /opt/hostedtoolcache/node/23.8.0/x64/bin/npm\nCorepack version: 0.31.0, Corepack path: /opt/hostedtoolcache/node/23.8.0/x64/bin/corepack\nPNPM version: 10.4.0, PNPM path: /usr/local/bin/pnpm\nCurrent $PATH: /opt/hostedtoolcache/node/23.8.0/x64/bin:/snap/bin:/home/runner/.local/bin:/opt/pipx_bin:/home/runner/.cargo/bin:/home/runner/.config/composer/vendor/bin:/usr/local/.ghcup/bin:/home/runner/.dotnet/tools:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin\n\n```\n\nNotice the difference: Node.js, NPM, and Corepack now correspond to the Node.js installation from `actions/setup-node`. However, `pnpm` is still the pre-installed version (or rather, it points to the pre-installed shims installed by the pre-installed Corepack).\n\nIn general, you won't notice any issues. However, it can introduce some really subtle bugs. For example, if you ever use `corepack`, after running that command, corepack will overwrite `pnpm` shims and you'll no longer be using that pre-installed corepack.\n\nArguably, it also affects the intent of using a pinned Node.js version in the first place by slightly deviating the GitHub actions environment from the actual development environment.\n\nIt may be more concerning in the future if the pre-installed corepack deviates significantly from the corepack version you are actually using. Corepack currently is still in its pre-1.0.0 stage and some commands (`hydrate`, `prepare`) have been deprecated.\n\nIt does raise the question why corepack is necessary to be ran before setting up Node.js. If you try the following:\n\n```yml\n- name: Set up Node.js environment\n  uses: actions/setup-node@v4\n  with:\n    node-version: ${{ matrix.node }}\n    cache: pnpm\n\n- name: Enable Node.js corepack shims\n  run: |\n    npm install -g corepack\n    corepack enable\n```\n\nThe output is:\n\n```\n\u003e Run actions/setup-node@v4\nAttempting to download 23.8.0...\nNot found in manifest. Falling back to download directly from Node\nAcquiring 23.8.0 - x64 from https://nodejs.org/dist/v23.8.0/node-v23.8.0-linux-x64.tar.gz\nExtracting ...\n/usr/bin/tar xz --strip 1 --warning=no-unknown-keyword --overwrite -C /home/runner/work/_temp/... -f /home/runner/work/_temp/...\nAdding to the cache ...\nDone\n\u003e Environment details\n**Error: Unable to locate executable file: pnpm. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.**\n```\n\nIn this case, the offending command being run is `pnpm store path --silent` which is run by `@actions/exec` to get a path to cache in `@actions/setup-node`. The output should be `/home/runner/.local/share/pnpm/store/v10`.\n\nIn this case, this is fine for most installations that don't update the store path, so it is always the same. There may be some subtle bugs, either if you set up .pnpmrc afterward, set `$PNPM_HOME`, `$XDG_DATA_HOME`, or some other ways the store path can be changed (see [pnpm/npmrc#store-dir](https://pnpm.io/npmrc#store-dir)), but those are mostly niche edge cases.\n\nHowever, it does mean that if you want to use the `corepack` shims with the Node.js version installed by `actions/setup-node` -- you can't. If you do, you'd have to cache the `pnpm` store path yourself.\n\nAs a thought experiment, here's a way that uses `corepack` shims with the Node.js version installed by `actions/setup-node`. Obviously, this is not recommended due to opening yourself up to security vulnerabilities.\n\n```yml\n- name: Temporarily alias `pnpm` to `corepack pnpm`\n  run: |\n    setup() {\n      unset -f main\n      local -r local_bin_dir=\"$HOME/.local/bin\" # By default, $HOME/.local/bin is in $PATH\n      local -r package_manager=\"$1\"\n\n      mkdir -p \"$local_bin_dir\"\n      cat \u003c\u003c EOF \u003e\u003e \"$local_bin_dir/$package_manager\"\n    #!/bin/bash\n\n    corepack $package_manager \"\\$@\"\n    rm \"$local_bin_dir/$package_manager\" # Remove alias after use\n\n    EOF\n\n      chmod u+x \"$local_bin_dir/$package_manager\" # Make alias executable for current user\n    }\n\n    setup pnpm\n\n- name: Set up Node.js environment\n  uses: actions/setup-node@v4\n  with:\n    node-version: ${{ matrix.node }}\n    cache: pnpm\n\n- name: Enable Node.js corepack shims\n  run: corepack enable\n```\n\nUnfortunately, the typical ways of using a `function`, `alias`, or a local file would not work in this case. \"@actions/exec\" explicitly executes tools that are only in the path, and for tools not in the path, they must be doubled quoted.\n\nWhat ends up happening is that when `@actions/setup-node` attempts to exec `pnpm store path --silent`, it will end up running `corepack pnpm store path --silent` instead. What this does is that it installs `pnpm` (and caches it) and then runs the command. Afterward, it removes the alias. Then, you can enable `corepack` on the new Node.js version, in which it installs the cached `pnpm` and creates the shims for it in the correct directory.\n\nThere's actually not much in the way of benefits of this approach. Corepack will be cached by `@actions/setup-node` so you won't need to download it again. You should be guaranteed that `pnpm` and `npm` always point to the correct installations.\n\nThere are some other concerns that may be worth considering. For example, if you explicitly set a `registry-url`, `scope`, or `always-auth` in `@actions/setup-node`, it will set a `.npmrc` file at `${{ env.NPM_CONFIG_USERCONFIG }}` (`/home/runner/work/_temp/.npmrc`). The intent is to overwrite the `userconfig` key in `.npmrc` (which is otherwise by default `$HOME/.npmrc`).\n\nIn that case, afterward, I do recommend having the following step after `@actions/setup-node` to explicitly guarantee the intended npm path is used. If you don't want to use their `.npmrc`, then it may be worth considering adding this to your own `.npmrc` file.\n\n```yml\n- name: Update `.npmrc` file\n  run: |\n    cat \u003c\u003c EOF \u003e\u003e ${{ env.NPM_CONFIG_USERCONFIG }}\n\n    ; pnpm\n    npm-path=`npm config get prefix`/bin/npm ; If you intend to use npm from `@actions/setup-node`\n\n    npm-path=/usr/local/bin/npm ; If you intend to use the pre-installed npm\n    EOF\n```\n\n## Conclusion\n\nI really don't think there is any concrete solution or best practice to these concerns. While they are mostly insignificant, they do present valid concerns I would argue are meaningful with setting up corepack in Github Actions. The best course of action is to be aware of these concerns and make a decision based on your own needs. Ideally, `@actions/setup-node` would have a way to explicitly toggle corepack before attempting to cache package managers, but I am empathetic to the fact that current guidance on using `corepack` as of right now is very confusing.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeremy-code%2Fgh-actions-pnpm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeremy-code%2Fgh-actions-pnpm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeremy-code%2Fgh-actions-pnpm/lists"}