Getting Started with npm Workspaces
The newest major release of npm, launched in October 2020, came out with a very anticipated feature (at least for me). The 7th version of the package manager introduced Workspaces.
The name may sound familiar. Other package managers such as Yarn and pnmp already ship with Workspaces for quite a while now. In fact, npm is not trying to reinvent the wheel. You can find similarities between all three Workspace implementations.
But what are Workspaces for? Workspaces help us managing repositories with multiple packages - more than one package.json
file. In projects like this, you usually have a complex dependency tree, with many packages depending on each other. This special type of repository is known as a monorepo.
In this post, you will see how npm Workspaces work, how to get started, and a comparison with other Workspace implementations. Iβve also provided a repository on GitHub with some sample code from the examples.
What changes with Workspaces?
Now, when you run npm install
in a multi-package repository, npmβs dependency tree manager is smart enough to scan your folders looking for all dependencies to install.
Dependencies are hoisted, meaning they get installed in the root node_modules
folder. This is done for performance reasons: if a dependency is shared by multiple packages, it gets saved only once in the root.
Your packages (the ones you created) also get symlinked in the root node_modules
folder. If two of your packages depend on each other, they get the reference from there.
For example, if you have this structure:
After running npm install
, your node_modules
folder will look like this:
If you have packages using the same dependency but on different versions, npm will create a node_modules
folder inside of one of the packages. For example, suppose package-a
uses lodash@4
while package-b
is still on lodash@3
:
When running npm install
, you will get the following result:
These are just a few examples to illustrate how the new dependency resolution works on Workspaces, thereβs certainly a lot more happening under the hood.
Getting started
Setting up
You can try out Workspaces today by updating your npm to version 7. To update, run this command on your terminal:
npm install -g npm@7
If you install Node.js 15 today, it should already come with npm 7.
You can use a similar structure as the ones showed before as a starting point for playing around with workspaces. For example:
.
βββ package.json
βββ packages
βββ package-a
β βββ package.json
βββ package-b
βββ package.json
Notice you still need a package.json
file in the root of your repository, even if it has no dependencies. In fact, itβs on that file that you define the location where your packages live.
Edit the root package.json
to reference your packages:
Now, when you run npm install
in the root of your repository, npm will be smart enough to install package-a
and package-b
βs dependencies.
I made a simple GitHub repository with this example in case you wanna check it in more detail. Hereβs the link: npm-workspaces-demo.
Using Workspaces
The npm CLI also introduced the --workspace
and --workspaces
flags. These flags can be added to many of the existing npm commands to run them in your sub-packages, instead of your root package.
For example, imagine package-a
and package-b
both have a script named βtestβ defined in their package.json
files:
You can run all the βtestβ scripts at once by adding the --workspaces
(plural) to your npm run
command:
That will give you the following output:
To run a command for a specific package, add the --workspace
(singular) flag:
The install
command also accepts the --workspace
flag:
Important! This was only introduced on npm@7.14.0
npm Workspaces vs.Β Yarn Workspaces
Yarn is the second biggest package manager for JavaScript, so it might be fair to make a comparison.
Yarn Workspaces is around for much longer. It was launched somewhere around 2017. The yarn workspaces
interface includes some extra tooling that npm is still catching up on. For example, an equivalent of yarn workspace <workspace> add <dependency>
(adding a dependency to a workspace) is still in the works Update: this feature was added on v7.14.0!.
You can also see some minor differences in the CLI (e.g. npm --workspaces
vs. yarn workspaces
), but the overall concepts remain the same. Yarn is constantly cited as prior art in the RFCs. I would be surprised to see big disparities between both CLIs.
Despite the differences, npm Workspaces is iterating fast. Since I first wrote this post in November 2020, many features have been released and RFCs have been accepted. It shouldnβt take long for npm to reach feature parity with Yarn and other package managers.
Using npm Workspaces today
βIβm starting a new monorepo project today, can I use npm Workspaces?β
You can, but keep reading.
If you are building a small monorepo project and need npm to just resolve your dependencies in a smart way, npm Workspaces alone should do the trick. You will get a similar experience as if you were using Yarn Workspaces.
But if youβre working on a bigger project, with multiple packages and a complex dependency tree, you might want to combine npm with a tool like Lerna.
Lerna has many useful commands to manage monorepos. Yarn has stated before that the goal of Yarn Workspaces is to provide low-level primitives for tools such as Lerna to use, not to compete with them. While npm hasnβt given a similar statement, I suspect they will follow the same approach as Yarn.
Whatβs next?
As I mentioned, npm Workspaces is still under active development and new features are being shipped fast. This is the second time I am updating this post, and I suspect it wonβt be the last.
If you want to keep up-to-date with Workspaces development, there are a few things you can do:
- Watch out for accepted RFCs to find out whatβs coming next;
- Subscribe to npm releases on GitHub.
- Follow me on Twitter, Iβll post anything interesting I can find. :)