DEV Community

Samuel Kinuthia
Samuel Kinuthia

Posted on

Mastering Monorepos with Lerna: A Comprehensive Guide

Introduction

Managing large-scale projects with multiple interdependent packages is a challenge for many development teams. Traditional approaches often involve using multiple repositories for each package, which can lead to overhead in code maintenance, dependency management, and collaboration.

Lerna, a powerful JavaScript tool, simplifies this challenge by introducing an efficient way to manage monorepos — repositories that host multiple packages within a single codebase. By utilizing Lerna, teams can benefit from streamlined dependency management, efficient workflows, and better control over their package releases.

In this ebook, we’ll explore what Lerna is, how to use it, and why it’s become an essential tool for developers working on large projects. Whether you're managing a small component library or a complex ecosystem of interdependent packages, this guide will help you unlock the full potential of Lerna.


Chapter 1: What is Lerna?

Lerna is an open-source tool designed to manage monorepos for JavaScript and TypeScript projects. It simplifies the task of managing multiple packages within a single repository by handling the following:

  • Dependency Management: Lerna automatically handles shared and package-specific dependencies across all projects in the monorepo.
  • Versioning and Publishing: Lerna simplifies the process of versioning and publishing multiple packages, whether using a unified or independent versioning strategy.
  • Efficient Workflows: Lerna allows you to execute tasks across all packages simultaneously, improving development efficiency.

Why Monorepos?

Monorepos are widely used in large-scale software development because they offer several advantages:

  1. Shared Codebase: Developers can reuse code between packages, reducing duplication and improving consistency.
  2. Simplified Collaboration: A single repository for multiple packages makes it easier for teams to collaborate without managing separate repos.
  3. Unified Build and Testing Processes: Teams can standardize build, test, and deployment processes across packages.

However, managing a monorepo can introduce challenges, particularly with dependency management, versioning, and publishing workflows. This is where Lerna shines.


Chapter 2: Installing and Setting Up Lerna

Prerequisites

Before setting up Lerna, ensure that you have Node.js and npm (or Yarn) installed on your system. Lerna supports both package managers.

Step 1: Installing Lerna

You can install Lerna globally using npm:

npm install --global lerna
Enter fullscreen mode Exit fullscreen mode

Or, add it as a dev dependency to your project:

npm install --save-dev lerna
Enter fullscreen mode Exit fullscreen mode

Step 2: Initializing a Lerna Monorepo

To start a new monorepo, navigate to your project folder and run:

lerna init
Enter fullscreen mode Exit fullscreen mode

This command creates a lerna.json file in the root of your project, which holds your Lerna configuration. It also sets up a packages folder, which will contain your individual packages.

Step 3: Adding Packages

In a Lerna monorepo, each package lives within its own subfolder in the packages directory. Each package must have its own package.json file to define its dependencies and configurations.

Directory structure example:

/my-project
  /packages
    /package-a
    /package-b
  lerna.json
  package.json
Enter fullscreen mode Exit fullscreen mode

Chapter 3: Dependency Management in Lerna

One of Lerna’s key features is its ability to manage dependencies across multiple packages. You can either install dependencies locally to each package or "hoist" shared dependencies to the root of the monorepo.

Independent Dependencies

When each package requires different dependencies, you can add dependencies specific to a package:

lerna add lodash --scope=package-a
Enter fullscreen mode Exit fullscreen mode

Hoisting Shared Dependencies

When multiple packages share the same dependency, Lerna allows you to hoist those dependencies to the root-level node_modules directory, reducing duplication. To enable hoisting, modify your lerna.json file:

{
  "hoist": true
}
Enter fullscreen mode Exit fullscreen mode

Bootstrapping

To install dependencies and link local packages, run:

lerna bootstrap
Enter fullscreen mode Exit fullscreen mode

Lerna will link packages that depend on each other and install all necessary external dependencies.


Chapter 4: Running Scripts Across Packages

Lerna enables you to run scripts (like build, test, or lint) across all packages at once. This is particularly useful for tasks that need to be performed across the entire monorepo.

Executing a Script Across All Packages

For example, to run the build script in every package, use:

lerna run build
Enter fullscreen mode Exit fullscreen mode

Lerna executes this command for every package that has a build script defined in its package.json.

Running Scripts in Specific Packages

You can target a specific package by using the --scope flag:

lerna run test --scope=package-a
Enter fullscreen mode Exit fullscreen mode

This flexibility allows you to manage large codebases efficiently without running unnecessary commands in packages that don't require it.


Chapter 5: Versioning and Publishing with Lerna

One of Lerna’s most powerful features is its ability to version and publish multiple packages from the same repository. Lerna offers two modes for versioning:

1. Fixed Mode

In fixed mode, all packages share a single version number. When you make a change to one package and publish it, the version number for all packages is incremented.

2. Independent Mode

In independent mode, each package can have its own version number, and changes to one package only affect its version. This is useful for projects where packages are released independently.

To switch to independent mode, update the lerna.json file:

{
  "version": "independent"
}
Enter fullscreen mode Exit fullscreen mode

Publishing Packages

To publish packages to npm, run:

lerna publish
Enter fullscreen mode Exit fullscreen mode

Lerna will automatically version the packages and publish them based on your configuration.


Chapter 6: Using Lerna with Yarn Workspaces

Lerna can be combined with Yarn Workspaces to further optimize dependency management. Yarn Workspaces allow for even more efficient hoisting of shared dependencies, improving install times and reducing node_modules size.

To enable Yarn Workspaces in Lerna, add the following to your lerna.json:

{
  "npmClient": "yarn",
  "useWorkspaces": true
}
Enter fullscreen mode Exit fullscreen mode

And modify your package.json:

{
  "workspaces": ["packages/*"]
}
Enter fullscreen mode Exit fullscreen mode

With Yarn Workspaces enabled, both Lerna and Yarn handle dependencies, ensuring a more efficient workflow.


Chapter 7: Advanced Lerna Usage

Filtering Commands

Lerna allows you to run commands on specific packages or exclude certain packages. This is useful when you only want to build or test part of your monorepo.

Example: Running a Command for Specific Packages

lerna run build --scope=package-a --scope=package-b
Enter fullscreen mode Exit fullscreen mode

Example: Excluding Packages

lerna run build --ignore=package-c
Enter fullscreen mode Exit fullscreen mode

Custom Lerna Commands

You can define custom Lerna commands for more specialized workflows. These are typically defined in the scripts section of your package.json and can include any commands you want to run across packages.


Chapter 8: Best Practices for Lerna Monorepos

  1. Organize Packages Logically: Group related packages together to improve code sharing and collaboration.
  2. Use Hoisting for Shared Dependencies: Hoisting shared dependencies saves space and reduces install times.
  3. Automate Testing: Use Lerna’s run commands to automate testing across all packages.
  4. Adopt Continuous Integration: Use CI/CD pipelines to automatically test, build, and publish packages in your monorepo.
  5. Leverage Yarn Workspaces: Combine Lerna with Yarn Workspaces for better dependency management.

Conclusion

Lerna is a powerful tool for managing monorepos, providing efficient solutions for dependency management, versioning, and publishing across multiple packages. By adopting Lerna, teams can streamline their development workflows, reduce complexity, and improve collaboration.

Whether you are building a large-scale JavaScript ecosystem or a simple component library, Lerna offers a flexible and scalable way to manage your projects. Keep experimenting with Lerna's advanced features, and apply best practices to maintain a clean, organized, and efficient codebase.


Appendix

Common Lerna Commands

  • lerna init: Initializes a new Lerna monorepo.
  • lerna bootstrap: Installs dependencies and links packages.
  • lerna add [package] --scope=[package-name]: Adds a dependency to a specific package.
  • lerna run [script]: Runs a script across all packages.
  • lerna publish: Publishes packages to npm.

Top comments (1)

Collapse
 
avinashd10 profile image
Avinashd

Nice and compact way to understand Lerna. Good read @samuel_kinuthia 👏