pnpm vs Lerna: filtering in a multi-package repository
Tags: pnpm, javascript, node, multipackagerepo
Published: 2018-09-02 21:53:00

---
title: pnpm vs Lerna: filtering in a multi-package repository
published: true
description: 
tags: pnpm, javascript, node, multi-package repo
cover_image: https://i.imgur.com/BIGkHaO.png
---

Everyone heard about [Lerna](https://github.com/lerna/lerna/), which is "A tool for managing JavaScript projects with multiple packages." A lot fewer devs heard about [pnpm](https://github.com/pnpm/pnpm), which is a fast, disk space efficient package manager for JavaScript. Both Lerna and pnpm try to improve tooling for multi-package repositories (MPR). For Lerna it was the reason for creation. For pnpm, MPR support is a nice bonus feature that is implemented via a set of commands called [recursive](https://pnpm.js.org/en/cli/recursive). Of course, there are many differences between how Lerna manages a multi-package repo vs pnpm. In this article, I want to compare one seemingly simple aspect: filtering.

Filtering in an MPR is important because, during development, changes are mainly made inside one or two packages. It wouldn't make sense to run commands on the whole repository if only a few packages were modified.

![](https://i.imgur.com/8zIYqAk.png)

## Filtering in Lerna

Filtering in Lerna (as of `v3.2.1`) is achieved by the following flags:

* `scope` - Include only packages with names matching the given glob.
* `include-filtered-dependents ` - Include all transitive dependents when running a command regardless of `--scope`, `--ignore`, or `--since`.
* `include-filtered-dependencies` - Include all transitive dependencies when running a command regardless of `--scope`, `--ignore`, or `--since`.
* `ignore` - Exclude packages with names matching the given glob.
* `private` - Include private packages. Pass --no-private to exclude private packages.
* `since` - Only include packages that have been updated since the specified [ref]. If no ref is passed, it defaults to the most recent tag.

These flags make filtering in Lerna quiet powerful. However, they are pretty hard to type. Let's say you downloaded a repository and want to work only on `login-page` component. You'd want to run installation for `login-page` and any of its dependencies:

```sh
lerna bootstrap --scope login-page --include-filtered-dependencies
```

Or maybe you changed a component called `site-header` and would like to run tests on all the dependent packages:

```sh
lerna run test --scope site-header --include-filtered-dependents
```

These flags are not only hard to type but also hard to remember and easy to mix up.

![](https://i.imgur.com/qlW1eEG.png)

## Filtering in pnpm

Unlike Lerna, pnpm uses a special package selector syntax to restrict its commands. So instead of memorizing a set of long flag names, you should only remember a very easy-to-remember selector syntax.

As of version `2.15.0`, these are the selectors that pnpm supports:

* `<pattern>` - Restricts the scope to package names matching the given pattern. E.g.: `foo`, `@bar/*`
* `<pattern>...` - Includes all direct and indirect dependencies of the matched packages. E.g.: `foo...`
* `...<pattern>` - Includes all direct and indirect dependents of the matched packages. E.g.: `...foo`, `...@bar/*`
* `./<directory>` - Includes all packages that are inside a given subdirectory. E.g.: `./components`
* `.` - Includes all packages that are under the current working directory.

These filters may be specified either via the `--filter` flag or after a `--`at the end of the command.

> Note: as of `v2.15.0`, filters after `--` are not supported by `run`, `exec`, `test`

So if you want to bootstrap `login-page` and all of its dependencies, this is the way you do it with pnpm:

```sh
pnpm recursive install -- login-page...
```

And if you want to run tests of `site-header` and all of its dependents, use the `...<pattern>` selector:

```sh
pnpm recursive test --filter ...site-header
```

Of course, you can combine as many selectors as you'd like:

```
pnpm recursive update -- ...site-header login-page... ./utils @style/*
```

The command above updates dependencies in:

* `site-header`
* dependents of `site-header`
* `login-page`
* dependencies of `login-page`
* all packages that are located in the `utils` directory
* all packages from the `@style` scope

* * *

pnpm might not have yet all the features that Lerna provides but for many users it might be enough already.

If you haven't heard about pnpm yet, I recommend reading also [Flat node_modules is not the only way](https://medium.com/pnpm/flat-node-modules-is-not-the-only-way-d2e40f7296a3) which explains the unique node_modules structure created by pnpm.

## Cheatsheet

| Lerna v3.2 | pnpm v2.15 |
| --- | --- |
| --scope my-component | -- my-component |
| --scope toolbar-* | -- toolbar-* |
| --scope my-component --include-filtered-dependencies | -- my-component... |
| --scope my-component --include-filtered-dependents | -- ...my-component |

* * *

*originally posted in [pnpm blog](https://medium.com/pnpm/pnpm-vs-lerna-filtering-in-a-multi-package-repository-1f68bc644d6a)*