Skip to content

An npm workspace lets you manage multiple packages in a single repository. Adding Nx to an npm workspace gives you cached tasks, affected-only builds, and faster CI, while npm keeps managing installs. This recipe sets up an npm workspace and then adds Nx.

An npm workspace is a repository whose root package.json has a workspaces field listing the directories that hold package.json files:

package.json
{
"name": "my-workspace",
"private": true,
"workspaces": ["apps/*", "packages/*"],
}

A common layout separates applications from shared packages:

  • Directorymy-workspace/
    • Directoryapps/
      • Directoryweb/
        • package.json
    • Directorypackages/
      • Directoryshared-ui/
        • package.json
    • package.json

npm does not use a workspace: protocol. To depend on another package in the workspace, reference it by name with * so npm links the local package:

apps/web/package.json
{
"name": "web",
"dependencies": {
"react": "^19.0.0",
"@my-workspace/shared-ui": "*",
},
}

Run npm install once at the root to install every package's dependencies and link the internal ones.

Nx layers task running and caching on top of your existing npm workspace. npm still installs and resolves packages; Nx makes your tasks cacheable and your CI affected-aware. Add it with one command, which works on any npm, Yarn, pnpm, or Bun workspace:

Terminal window
npx nx@latest init

Your existing package.json scripts keep working. Nx infers a project for each package.json in your workspace and runs its scripts with caching, with no project.json or extra configuration required.

Before Nx, npm runs a script across packages, but it runs every task every time and has no notion of which packages a change affects:

Terminal window
npm run build --workspaces # every package
npm run build --workspace=web # a single package

After nx init, run the same scripts through Nx:

Terminal window
nx run-many -t build # every project
nx build web # a single project
nx affected -t build # only projects touched by your changes

The first run executes your scripts. A second run with no changes is restored from the cache instantly, and nx affected skips the projects your change does not touch.

nx init writes an nx.json with targetDefaults that control which targets are cached:

nx.json
{
"targetDefaults": {
"build": {
"cache": true,
"dependsOn": ["^build"],
},
},
}

cache: true makes a target cacheable: Nx hashes each project's inputs (source files, dependencies, and config) and restores its outputs from the cache when nothing has changed. dependsOn: ["^build"] builds a project's dependencies first. Nothing is cached unless you opt in, so you stay in control.

In CI, turn on remote caching and task distribution to share the cache across machines and parallelize tasks. For a deeper walkthrough, see Adding Nx to an NPM/Yarn/PNPM Workspace.