npm workspaces: an introduction
Workspaces provides tooling for managing multiple packages within a single repository. npm’s implementation aids with more efficiently managing shared depedencies, and running scripts across packages.
Setting up
Given a repository npm-workspaces
with two packages a
and b
:
./npm-workspaces
├── package.json
└── packages
├── a
│ └── package.json
└── b
└── package.json
Workspaces are defined in the root package.json
under the workspaces
property:
{
"name": "npm-workspaces",
"workspaces": ["packages/a", "packages/b"]
}
Dependencies
Running npm install
at the root will search for all dependencies in the multi-package repository to install.
All dependencies are hoisted to the root node_modules
unless their versions differ across packages, so dependencies shared by multiple packages are only saved once. Packages are also treated as dependencies, and are automatically symlinked in the root node_modules
.
Installing the dependency lodash
for a specific workspace a
(from anywhere within the repository):
npm i lodash -w a
Then generates the following tree:
./npm-workspaces
├── node_modules
│ ├── a -> ../packages/a
│ ├── b -> ../packages/b
│ └── lodash
├── package-lock.json
├── package.json
└── packages
├── a
│ ├── package.json
└── b
└── package.json
If the same dependency is shared by package b
then the above tree is unchanged and the dependency is still only saved once in the root node_modules
, as confirmed below:
/npm-workspaces ❯ npm ls
npm-workspaces@ /npm-workspaces
├─┬ a@1.0.0 -> ./packages/a
│ └── lodash@4.17.21
└─┬ b@1.0.0 -> ./packages/b
└── lodash@4.17.21 deduped
If a package diverts it’s version of a shared dependency, then it will have its own node_modules
within the package. Workspaces will continue to share a single package-lock.json
at the root:
./npm-workspaces
├── node_modules
│ ├── a -> ../packages/a
│ ├── b -> ../packages/b
│ ├── lodash
├── package-lock.json
├── package.json
└── packages
├── a
│ ├── node_modules
│ │ └── lodash
│ └── package.json
└── b
└── package.json
Running scripts
npm workspaces supports running workspace scripts from anywhere within the repository. Running the script start
for workspace a
:
npm run start -w=a
Or for multiple workspaces:
npm run start -w=a -w=b
npm run start -ws # all
However, the above will fail if a specified workspace does not support the script start
. To ignore workspaces missing the target script:
npm run dev -ws --if-present