CalcSnippets
DevOps 4 min read

Use pnpm Workspace Filters to Run One Package Without Guessing

pnpm filters select packages by name, path, and dependency relationship. Start with an explicit package selector and inspect the selected workspace before running a destructive script.

Start with the package identity

In a monorepo, pnpm test at the root may run only the root script or a configured recursive task. To target one workspace, use a filter that matches the package name:

pnpm --filter @acme/web test

To include dependencies needed by that package, prefix the selector with ...; to select dependents, suffix it. For example, --filter ...@acme/web includes the package and its dependency workspaces. These relationships matter when a library change affects an app but the app's build depends on several local packages.

Check the selection before broad commands

Use pnpm --filter @acme/web exec pwd or list workspace packages with pnpm -r list --depth -1 to confirm what the selector resolves to. A typo can select nothing, and a broad glob can select more packages than expected. This is especially important for commands that publish, migrate, or delete generated output.

For changed-package CI, derive the filter from Git changes carefully and include dependents when the test requires them. Do not assume dependency direction: ...pkg and pkg... are intentionally different. Quote selectors in shells when they contain glob characters so the shell does not expand them against filesystem paths first.

Keep scripts package-local and let pnpm provide workspace context. If a script works from one package directory but fails at the root, inspect its assumptions about current working directory rather than adding hardcoded relative paths. Filters improve speed only when the selected graph still covers the behavior under test.

Choose the direction from the change you are testing

Workspace filter syntax encodes graph direction, so write down whether you need dependencies or dependents. If a shared library changes, testing the library itself checks its local contract, while selecting its dependents checks how consuming applications behave. Those are separate questions. A filter that includes dependencies of an application does not necessarily include every application that consumes a changed library. Verify the selected package list before relying on a changed-package CI job.

Use package names when scripts should survive directory moves, and use paths when the task is explicitly scoped to a known folder. Name selectors can be ambiguous if a monorepo accidentally contains duplicate package names; path selectors can be fragile if the directory layout changes. Keep selectors in the repository's CI configuration or package scripts when they represent a stable team workflow, rather than asking every contributor to memorize a long expression.

Make destructive and publishing tasks auditable

Before running a filter that publishes, migrates, cleans, or rewrites generated files, print the selected projects and inspect the list. A selector can resolve to no projects, one project, or a broad set after a glob expansion. In shells, quote patterns so the shell does not expand them against the current directory before pnpm sees them. For a release job, assert that the selected package names match an expected allowlist before publishing.

Keep package scripts independent of an assumed current working directory. pnpm runs workspace scripts with package context, but shell scripts may still use relative paths that differ when invoked directly from the package versus recursively from the root. Resolve repository paths from the script location or pass them explicitly. This makes a filter useful as a selection mechanism instead of a hidden change to filesystem assumptions.

When optimizing CI, compare the filtered test set with a full workspace run periodically. A fast filtered job is valuable only if it does not omit a consumer affected by the change. Keep a small integration job that exercises the important dependency edges, and document why the filter includes or excludes dependencies and dependents. That makes the selection logic reviewable when the workspace graph evolves.

For large workspaces, verify that the command is invoked from the directory where pnpm finds the intended root. A package can contain a valid package.json while the workspace manifest is absent or a glob excludes its directory. Compare pnpm's discovered root with the expected repository root and inspect recent package moves. This gives a reproducible diagnosis instead of a guess based on folder names.

Use an explicit -C location in automation when the command can be launched from more than one directory. Print the selected package names before running tests or releases. These two details make a filter failure easy to reproduce from CI logs and reduce the temptation to replace a precise selector with a dangerous wildcard.

Keep reading

Related guides