Logo Vincent
Back to all posts

Using npm Workspaces for Frontend Monorepos

Web
Using npm Workspaces for Frontend Monorepos

Preface

I had been using lerna to manage frontend monorepos projects.

After upgrading lerna today, I found that the bootstrap command is no longer supported,

replaced by npm’s workspaces-related commands.

lerna bootstrap

For lerna usage, see this article:

一文学会用Lerna管理多个npm包

The lerna bootstrap command

is used to install dependencies for packages and manage inter-dependencies.

Here’s an example using a monorepos frontend project:

URL: https://github.com/uikoo9/offline-to-online

This project has 4 packages:

Their relationships are as follows:

As you can see, qiao-is-online depends on offline-to-online and qiao-ping.

After running lerna bootstrap, you can see that qiao-is-online’s dependencies are locally linked:

As you can see,

lerna’s previous bootstrap command mainly:

  1. Installs dependencies for each package

  2. If a dependency is a local package, it creates a local link instead of downloading it

However, lerna removed this command in version 7.0.0.

The prompt is as follows:

Lerna’s official explanation is here: https://lerna.js.org/docs/legacy-package-management

The gist is that package managers like npm already have the bootstrap capability,

so the command was removed in favor of npm’s workspaces feature.

npm workspaces

npm’s workspaces documentation: https://docs.npmjs.com/cli/v9/using-npm/workspaces

Let’s compare it with lerna bootstrap.

lerna.json vs package.json

The packages property in lerna.json declares the package locations.

For example, the config below tells lerna that packages are in the packages folder:

{
  "packages": ["packages/*"],
  "version": "3.1.6",
  "command": {
    "version": {
      "allowBranch": "master"
    },
    "publish": {
      "allowBranch": "master",
      "message": "chore(release): publish"
    }
  }
}

The workspaces property in package.json is similar.

For example, the config below tells npm that packages are in the packages folder:

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

To use npm workspaces,

you need to modify lerna.json accordingly —

remove the packages property from lerna.json:

{
  "$schema": "node_modules/lerna/schemas/lerna-schema.json",
  "version": "3.1.8",
  "command": {
    "version": {
      "allowBranch": "master"
    },
    "publish": {
      "allowBranch": "master",
      "message": "chore(release): publish"
    }
  }
}

node_modules Location

After lerna bootstrap installs dependencies by default,

each package’s dependencies are in its own folder. For example:

qiao-is-online’s dependencies are in its own node_modules folder.

After adding the workspaces property to npm,

running npm i will install all package dependencies to the root node_modules.

Although everything is installed at the root, locally interdependent packages are still linked.

The effect is similar to lerna bootstrap —hoist.

However, if a dependency exists at the root level

and also in a package under packages,

and the two versions differ — for example:

You can see that uuid in packages/qiao-encode depends on version 9.0.0,

while the root-level lerna depends on 8.3.2.

In this case, when using npm workspaces,

npm i will install the package’s dependency in the package’s own folder.

Summary

Lerna’s lerna bootstrap command

can be replaced by npm’s workspaces property and the npm i command.

© 2026 Vincent. All rights reserved.