workspaces array in the root package.json, and a single npm install sets them all up together.Guide
One repository, several packages, managed together. That's a monorepo — and npm has it built in.
Imagine you're building a web app and a small library it uses, and you want them in the same repository so they're easy to change together. Without help, each folder would need its own install and you'd have to manually link them. Workspaces are npm's built-in way to manage many packages inside one repo — a setup often called a monorepo.
Heads up: this website is a single package, so it doesn't use workspaces — you only need them once you have several packages living together. This chapter is "here's how, when you do".
You have one root package.json that lists where the sub-packages
live, and each sub-package has its own package.json as normal:
my-repo/
├─ package.json // the root — declares the workspaces
├─ packages/
│ ├─ app/
│ │ └─ package.json // a package named "app"
│ └─ ui/
│ └─ package.json // a package named "ui" The root package.json just needs a workspaces field:
{
"name": "my-repo",
"private": true,
"workspaces": ["packages/*"]
}
The root is marked "private": true because it's only a container — you'd never
publish the repo wrapper itself.
The headline benefit: a single npm install at the root sets up all the
packages at once. It also creates symlinks so that when "app" depends on "ui", it uses your
local "ui" directly — edit one, the other sees it immediately, no publishing needed.
Install the whole monorepo
$ npm install # run once, in the repo root npm install in the terminal'Hoisting' means common dependencies are stored once at the root instead of duplicated in each package — saving lots of space.
The -w (workspace) flag targets one package. Use it to add a dependency to just that
package, or to run one package's script:
Target one workspace
$ npm install lodash -w ui # add a dep to the 'ui' package only
$ npm run build -w app # run app's build script
$ npm run test --workspaces # run test in every package -w <name> targets a single package; --workspaces fans out to all of themThe name after -w is the package's name from its own package.json, not the folder path.
Beyond npm's built-in workspaces there are dedicated monorepo tools (Turborepo, Nx, pnpm workspaces) that add caching and smarter task running. They build on the same idea — start with npm workspaces, reach for those only when a big repo gets slow.
Up next: bending npm to your will with .npmrc configuration and custom registries.
FAQ
workspaces array in the root package.json, and a single npm install sets them all up together.npm install once in the repo root. npm installs every workspace, hoists shared dependencies to a single root node_modules, and symlinks the packages so they can use each other directly.-w flag: npm run build -w app runs the "app" package's build. --workspaces (plural) runs the script in every package instead.