Installing dependencies in a Lerna monorepo involves both setting up existing package dependencies and adding new ones to specific packages. While Lerna historically provided its own commands like lerna bootstrap
, modern Lerna workflows often leverage native package manager workspaces (like npm or Yarn workspaces) for a streamlined experience.
Understanding Dependency Management in Lerna
Lerna is a tool that optimizes the management of multi-package repositories (monorepos) with Git and npm. It helps in hoisting common dependencies to the root of the monorepo, linking local packages, and ensuring consistent versioning. When working with Lerna, you're primarily dealing with two scenarios for dependency installation:
- Initial or General Installation: Setting up all existing dependencies across your monorepo.
- Adding New Dependencies: Installing a new dependency to one or more specific packages within your monorepo.
General Installation for Existing Dependencies
For a fresh clone of your Lerna monorepo or after changes in package.json
files, the primary way to install all existing dependencies across all packages is by running your package manager's install command at the monorepo root.
-
Using npm (recommended with modern Lerna):
npm install
This command, when executed in the root of a monorepo configured with
workspaces
in itspackage.json
, will install all dependencies for the root and all defined packages. This is the most common and efficient method for initial setup or after pulling changes. -
Using
lerna bootstrap
(older Lerna versions or specific needs):lerna bootstrap
Prior to Lerna v7,
lerna bootstrap
was the go-to command. It handlesnpm install
(or Yarn/pnpm equivalent) for each package, links local packages, and hoists common dependencies. While still available, leveraging native workspaces withnpm install
is generally preferred for its simplicity and direct integration with your chosen package manager.
Adding New Dependencies to Specific Packages
When you need to introduce a new dependency to just one or a few specific packages within your Lerna monorepo, you have powerful options using either Lerna's add
command or the native npm install -w
(npm workspaces) command.
1. Using lerna add <dependency> --scope <package>
Lerna provides a dedicated command to add a new dependency to a targeted package or set of packages within your monorepo. This command is particularly useful for maintaining control over dependency scope.
-
Syntax:
lerna add <dependency-name>[@version] --scope=<package-name-or-glob> [--dev] [--exact] [--peer]
-
How it works:
- It installs the specified dependency.
- It adds the dependency to the
package.json
of the targeted package(s). - It then runs a general
install
(likenpm install
) at the root to ensure all dependencies are correctly linked and hoisted.
-
Example: To add
lodash
as a production dependency to a package namedmy-ui-component
:lerna add lodash --scope=my-ui-component
This command will add
lodash
to thedependencies
section ofpackages/my-ui-component/package.json
. -
Example for
devDependencies
: To addjest
as a development dependency to an internal utility package:lerna add jest --scope=my-utils --dev
2. Using npm install <dependency> -w <package>
(npm Workspaces)
For monorepos utilizing npm workspaces (which is common with modern Lerna setups), you can directly use npm's --workspace
(or -w
) flag to install dependencies into specific packages. This method is often preferred for its directness and alignment with standard npm practices.
-
Syntax for a single package:
npm install <dependency-name>[@version] -w <package-name-or-path> [--save-dev] [--save-exact]
-
How it works:
- The
-w
flag tells npm to perform the installation within the specified workspace (package). - The dependency is added to the
package.json
of that workspace. - Npm then handles the installation, respecting hoisting rules configured for the monorepo.
- The
-
Example: To add
axios
as a production dependency to a package located atpackages/api-client
:npm install axios -w packages/api-client
This command will add
axios
to thedependencies
section ofpackages/api-client/package.json
. -
Example for
devDependencies
: To addtypescript
as a development dependency to ashared-types
package:npm install typescript -w packages/shared-types --save-dev
3. Using npm install <dependency> -w <package1> -w <package2>
(Multiple Packages)
The npm install -w
command can be used multiple times to add the same dependency to several specific packages simultaneously.
-
Syntax for multiple packages:
npm install <dependency-name>[@version] -w <package1-name-or-path> -w <package2-name-or-path> [...] [--save-dev]
-
Example: To add
react-query
to bothpackages/web-app
andpackages/admin-dashboard
:npm install react-query -w packages/web-app -w packages/admin-dashboard
This will add
react-query
to thedependencies
section of bothpackages/web-app/package.json
andpackages/admin-dashboard/package.json
.
Summary of Dependency Installation Methods
Method | Description | Use Case | Example |
---|---|---|---|
npm install (at monorepo root) |
Installs all existing dependencies for the entire monorepo. | Initial setup, after pulling changes, general dependency updates. | npm install |
lerna add <dep> --scope=<pkg> |
Adds a new dependency to a specific package(s) using Lerna's dedicated command. | Targeted dependency addition, especially when not using native workspaces. | lerna add react --scope=my-app |
npm install <dep> -w <pkg> |
Adds a new dependency to a specific package using npm workspaces. | Modern, targeted dependency addition for npm workspace users. | npm install styled-components -w packages/design-system |
npm install <dep> -w <pkg1> -w <pkg2> |
Adds a new dependency to multiple specific packages using npm workspaces. | Adding the same dependency to several packages efficiently. | npm install firebase -w packages/auth -w packages/data-service |
Practical Insights and Best Practices
- Leverage Workspaces: For modern Lerna setups, configuring
workspaces
in your rootpackage.json
is highly recommended. This allows you to use your package manager's native commands (npm install
,npm add
,npm rm
) with the--workspace
flag, simplifying dependency management.// root package.json { "name": "my-lerna-monorepo", "version": "1.0.0", "private": true, "workspaces": [ "packages/*" ], "scripts": { "start": "lerna run start", "test": "lerna run test" }, "devDependencies": { "lerna": "^7.x.x" } }
- Root
devDependencies
for Tooling: Place common development tools (like ESLint, Prettier, Jest, TypeScript) in the rootpackage.json
'sdevDependencies
. This allows all packages to access them without duplicating installations. - Internal Package References: Lerna (via workspaces) automatically handles linking your internal packages, so you can
import { MyComponent } from 'my-ui-component'
as if it were an external dependency, even ifmy-ui-component
is another package within your monorepo. - Version Consistency: Strive for consistent versions of shared dependencies across your monorepo to avoid conflicts and simplify maintenance. Tools like Renovate Bot or Dependabot can help automate dependency updates.
- Understanding Hoisting: When a dependency is used by multiple packages and they all request the same version, Lerna and workspaces will often "hoist" that dependency to the monorepo root
node_modules
to save disk space and installation time.
By understanding these methods and best practices, you can effectively manage dependencies in your Lerna monorepo, ensuring a smooth development workflow.