How to Use npm Workspaces for Monorepos

This article provides a practical guide on how to configure and manage a monorepo using native npm workspaces in a Node.js ecosystem. You will learn how to initialize a workspace-enabled project, structure your codebase, manage shared dependencies, and run scripts across multiple packages efficiently from a single root directory.

What are npm Workspaces?

Introduced in npm v7, workspaces allow you to manage multiple packages within a single root package. This eliminates the need for complex external tools for basic monorepo orchestration. It automatically handles symlinking, enabling packages within your repository to reference one another local-first.

Step 1: Initialize the Root Package

To begin, create a new directory for your monorepo and initialize it with a package.json file.

mkdir my-monorepo
cd my-monorepo
npm init -y

Open the package.json file and add the workspaces property. This property accepts an array of globs pointing to the directories containing your sub-packages.

{
  "name": "my-monorepo",
  "version": "1.0.0",
  "private": true,
  "workspaces": [
    "packages/*"
  ]
}

Note: Marking the root package as "private": true prevents it from being accidentally published to the npm registry.

Step 2: Create Sub-Packages

Next, create a packages directory and set up your individual workspaces (for example, a shared utility library and an API service).

mkdir -p packages/shared packages/api

Initialize a package.json in each sub-package:

packages/shared/package.json:

{
  "name": "@my-monorepo/shared",
  "version": "1.0.0",
  "main": "index.js"
}

packages/api/package.json:

{
  "name": "@my-monorepo/api",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "@my-monorepo/shared": "^1.0.0"
  }
}

Step 3: Install Dependencies

Run npm install from the root directory. npm will resolve the dependency tree, symlink @my-monorepo/shared into the root node_modules folder, and make it available to @my-monorepo/api without publishing it to an external registry.

To add an external dependency (like lodash) to a specific workspace, use the -w (workspace) flag from the root:

npm install lodash -w @my-monorepo/shared

To add a development dependency to all workspaces, use the -ws flag:

npm install rimraf --save-dev -ws

Step 4: Running Scripts

You can run scripts defined in individual packages directly from the root using the -w flag. For example, if @my-monorepo/api has a start script, run:

npm run start -w @my-monorepo/api

To run a specific script (like a test or build script) across all workspaces simultaneously, use the -ws flag:

npm run test -ws