Files
pnpm/pnpm11/docs/cli/recursive.md
Zoltan Kochan 316ec14c4b fix(worker): size the worker pool by the cgroup CPU quota (#17385)
The worker pool and the default workspaceConcurrency took the CPU count
from os.availableParallelism(), which counts the CPUs in the process's
affinity mask. In a container with a cgroup CPU quota smaller than that
mask, such as a Kubernetes pod with a 4-CPU limit on a 233-CPU node,
pnpm 11 created 232 workers per install, and four concurrent installs
exhausted a 16 GiB memory limit while the workers were still loading.

Node's libuv does try to apply the quota, but its cgroup v1 parser
looks for ":cpu," and keeps "cpuacct:" in the path it builds, so it
never finds the quota file there, and both it and Rust's standard
library give up when the cgroup path from /proc/self/cgroup is not
mounted under /sys/fs/cgroup, as happens with a host cgroup namespace
and a bind-mounted controller.

A new package, `@pnpm/os.available-parallelism`, reads the quota itself:
the smallest limit/period walking from the process's cgroup up to the
hierarchy root, for cgroup v2 (cpu.max) and v1 (cpu.cfs_quota_us and
cpu.cfs_period_us), rounded down and floored at 1 like Rust's
std::thread::available_parallelism, which pnpm 12 already uses. The
cgroup directory is located through /proc/self/mountinfo, which says
which cgroup each mount shows, so a container that sees only its own
cgroup bind-mounted at /sys/fs/cgroup is read correctly; the standard
mount points are the fallback. The worker pool and the config reader's
workspace-concurrency default both use it, so the two stay in step.

pnpm 12 is unaffected: every Rust pool is sized with
std::thread::available_parallelism, which honours the quota.

Closes pnpm/pnpm#17382
2026-10-26 17:20:51 +01:00

124 lines
3.2 KiB
Markdown

---
id: recursive
title: pnpm -r, --recursive
---
Aliases: `m`, `multi`, `recursive`, `<command> -r`
Runs a command in every project of a workspace, when used with the following commands:
* `install`
* `list`
* `outdated`
* `publish`
* `pack`
* `rebuild`
* `remove`
* `unlink`
* `update`
* `why`
Runs a command in every project of a workspace, excluding the root project,
when used with the following commands:
* `exec`
* `run`
* `test`
* `add`
If you want the root project be included even when running scripts, set the [includeWorkspaceRoot] setting to `true`.
Usage example:
```sh
pnpm -r publish
```
By default, recursive `run`, `exec`, and `test` execute projects in
topological order: dependencies run before their dependents. Use `--no-sort`
to disable graph ordering, or `--parallel` to start tasks without waiting for
dependencies.
## Options
### --link-workspace-packages
* Default: **false**
* Type: **true, false, deep**
Link locally available packages in workspaces of a monorepo into `node_modules`
instead of re-downloading them from the registry. This emulates functionality
similar to `yarn workspaces`.
When this is set to deep, local packages can also be linked to subdependencies.
Be advised that it is encouraged instead to use [`pnpm-workspace.yaml`] for this setting, to
enforce the same behaviour in all environments. This option exists solely so you
may override that if necessary.
[`pnpm-workspace.yaml`]: ../workspaces.md#linkworkspacepackages
### --workspace-concurrency
* Default: **the smaller of 4 and the number of available CPU cores**
* Type: **Number**
Set the maximum number of tasks to run simultaneously. For unlimited concurrency
use `Infinity`.
In a container with a CPU quota, such as a Kubernetes CPU limit, the quota is the
number of available CPU cores when it is smaller than the number of CPUs the
container may run on. A fractional quota is rounded down, to at least 1.
You can set the `workspace-concurrency` as `<= 0` and it will use the number of available CPU cores as: `max(1, (number of available CPU cores) - abs(workspace-concurrency))`
### --[no-]bail
* Default: **true**
* Type: **Boolean**
If true, stops when a task throws an error.
This config does not affect the exit code.
Even if `--no-bail` is used, all tasks will finish but if any of the tasks fail,
the command will exit with a non-zero code.
Example (run tests in every package, continue if tests fail in one of them):
```sh
pnpm -r --no-bail test
```
### --[no-]sort
* Default: **true**
* Type: **Boolean**
When `true`, commands follow the workspace dependency graph. Recursive `run`
also applies relationships from the [`tasks` setting]. Pass `--no-sort` to
remove graph ordering. This also makes `tasks`, `--reverse`, and `--resume-from`
inapplicable.
Example:
```sh
pnpm -r --no-sort test
```
### --reverse
* Default: **false**
* Type: **boolean**
When `true`, dependency edges are reversed. For recursive `run`, this reverses
the resolved task graph, including relationships declared with `dependsOn`.
```sh
pnpm -r --reverse run clean
```
### --filter &lt;package_selector\>
[Read more about filtering.](../filtering.md)
[includeWorkspaceRoot]: ../workspaces.md#includeworkspaceroot
[`tasks` setting]: ../workspace-task-orchestration.md