Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
362 views26 pages

Lerna-7 2 0

Lerna is a tool for managing JavaScript projects with multiple packages. It allows running commands across all packages, managing dependencies and publishing packages to npm. Lerna delegates task running to Nx, which caches results for improved speed and allows distributing tasks across multiple machines. To use Lerna, install it with npm install lerna and run commands like lerna run to build or test packages. Lerna works best when combined with Nx Cloud for additional features like sharing caches between organizations.

Uploaded by

Naman Gupta
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
362 views26 pages

Lerna-7 2 0

Lerna is a tool for managing JavaScript projects with multiple packages. It allows running commands across all packages, managing dependencies and publishing packages to npm. Lerna delegates task running to Nx, which caches results for improved speed and allows distributing tasks across multiple machines. To use Lerna, install it with npm install lerna and run commands like lerna run to build or test packages. Lerna works best when combined with Nx Cloud for additional features like sharing caches between organizations.

Uploaded by

Naman Gupta
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

Introduction

Lerna is the original monorepo tool for JavaScript/TypeScript. It has been around for many years and is used by tens of thousands of projects, including React and Jest.

It solves two of the biggest problems of JavaScript/TypeScript monorepos:

Lerna runs a command against any number of projects, and it does it in the most efficient way, in the right order, and with the possibility to distribute that on multiple machines.
Lerna manages your publishing process, from version management to publishing to NPM, and it provides a variety of options to make sure any workflow can be accommodated.

Nx (the company behind the open source build system of the same name) has taken over stewardship of Lerna. Nx is a build system developed by ex-Googlers and utilizes many of the techniques used by internal Google
tools. Lerna v5 was the first release under this new stewardship, updating outdated packages and starting to do some cleanup on the repository itself. Starting with v6+, Lerna delegates task scheduling work to Nx's battle
tested, industry-leading task runner, meaning lerna run gets the benefits of caching and command distribution for free!

Why Lerna?​
Super Fast! Lerna is fast, even faster than most comparable solutions out there (see this benchmark to learn more). How? Under the hood, Lerna v6+ uses Nx to run tasks. Learn more about running tasks here.
Computation Caching - Lerna knows when the task you are about to run has been executed in the past. Instead of running it, Lerna will restore the files and replay the terminal output instantly. Plus, this cache can
be shared with your co-workers and CI. When using Lerna, your whole organization will never have to build or test the same thing twice. Read more »
Configuration-Free Distributed Task Execution Lerna can distribute any command across multiple machines without any configuration, while preserving the dev ergonomics of running it on a single machine. In
other words, scaling your monorepo with Lerna is as simple as enabling a boolean flag. See the examples of how enabling DTE can make you CI 20 times faster. Read more »
Beautiful Terminal Output Monorepos can have hundreds or thousands of projects. Printing everything on every command makes it hard to see what fails and why. Thankfully, Lerna does a much better job.
Powerful Graph Visualizer Lerna comes with a powerful interactive visualizer simplifying the understanding of your workspaces. Read more »
Publishing to NPM Lerna is the ultimate tool for publishing multiple packages to npm. Whether the packages have independent versions or not, Lerna has you covered. Read more »
Easy to Adopt Even with all these capabilities, Lerna is very easy to adopt. It requires close-to-zero configurations. Want to see how?

Getting Started

Lerna comes with a dedicated init command to assist you with both adding lerna to an existing repo, or creating one from scratch.

Starting from scratch​


In the simplest case, lerna init can be used to create a new repository in an empty directory. For that, we can run the following commands:
# Create an empty directory
mkdir ./new-lerna-workspace
# Change into the new directory
cd ./new-lerna-workspace
# Initialize lerna (using --dryRun to preview the changes)
npx lerna init --dryRun

Note that we have passed the --dryRun flag here, this allows us to see a preview of the changes that lerna init will make to our file system. This allows us to tweak the values of any other arguments we pass to lerna
init (such as --exact or --independent ) without having to worry about undoing any mistakes.

Once we are happy with the changes it will make, we can simply repeat the npx lerna init command but leave off the --dryRun flag.

You will now be up and running with a working git repository, including npm workspaces, with lerna available to create, version and publish any packages you wish to develop.

Adding lerna to an existing repo​


If you already have an existing repo, you can still add lerna to it using lerna init.

info

Lerna is not responsible for installing and linking your dependencies in your repo, your package manager is much better suited to that task.

Instead, we strongly recommend configuring your package manager of choice to use its workspaces feature:

npm (https://docs.npmjs.com/cli/using-npm/workspaces)
yarn (https://yarnpkg.com/features/workspaces)
pnpm (https://pnpm.io/workspaces)

When initializing lerna on an existing repo, it will need a way to know what packages it should operate on. If you are using your package manager's workspaces feature (see note above), then lerna will default to using the
workspaces patterns you have already configured. No extra arguments are required.

Alternatively, you can manually specify a set of patterns to match against instead by using the --packages flag for lerna init:
# Passing a single pattern
npx lerna init --packages="packages/*"
# Passing multiple patterns
npx lerna init --packages="foo/*" --packages="bar/*"

Lerna and Nx
Nrwl (the company behind the open source build system Nx) has taken over stewardship of Lerna. Nx is a build system developed by ex-Googlers and utilizes many of the techniques used by internal Google tools. Lerna
uses Nx to detect packages in the workspace and dependencies between them. Lerna defers to Nx's powerful task runner to run scripts, allowing you to run them in parallel, cache results, and distribute them across multiple
machines, all while ensuring that dependencies between packages are respected. For a complete list of which Lerna versions are compatible with which Nx versions, see the Lerna and Nx Version Matrix.

The following is a high level overview of what each tool provides. Lerna can continue to be used by itself, and adding Nx Cloud for free on top can dramatically improve what you're already doing.

Lerna​
Features​
1. Version - Automatically increment versions of packages, generate changelog information, create Github releases etc.
2. Publish - Automatically create tags and publish packages to package registries, such as npm
Cost​
Free and open source

Set up​
npm install lerna
npx lerna init

Nx​
Features​
1. Run only tasks affected by a code change
2. Run prerequisite tasks first
3. Cache task results locally
4. Visualize the project graph
5. Nx Console - Visual Studio Code plugin

Cost​
Free and open source

Set up​
npx lerna add-caching
Continue using Lerna as usual

note

Lerna defers to Nx's power task runner behind the scenes to detect task dependencies. Some options for lerna run behave differently than in older versions of Lerna. See Using Lerna (Powered by Nx) to Run Tasks for
more details on what differs from older versions of Lerna.

Nx Cloud​
Features​
1. Share cached task results across the organization
2. Distribute task execution efficiently across agent machines

Cost​
Free for open source projects

For closed source repositories, the first 500 computation hours per month are free. Most repositories do not exceed this limit. $1 per computation hour after that.

Set up​
npx nx connect-to-nx-cloud
nx generate @nrwl/workspace:ci-workflow (or set up your CI manually)
Continue using Lerna as usual

None

Run Tasks
Monorepos can have hundreds or even thousands of projects, so being able to run npm scripts against all (or some) of them is a key feature of a tool like Lerna.

Definitions​
Command - anything the developer types into the terminal (e.g., lerna run build --scope=header --concurrency=5 ).
Target - the name of an npm script (e.g., build)
Task - an invocation of an npm script (e.g., header:build ).

Example Repository​
Examples are based on this repository, so feel free to clone it and follow along.

Run Everything​
Each project has the test and build scripts defined.

Run:
npx lerna run build

This will build the projects in the right order: footer and header and then remixapp.

Terminal Output
✔ header:build (501ms)
✔ footer:build (503ms)
✔ remixapp:build (670ms)
————————————————————————————————————————————————————————————————
> Lerna (powered by Nx) Successfully ran target build for 3 projects (1s)

Note that Lerna doesn't care what each of the build scripts does. The name build is also not special: it's simply the name of the npm script.

Run a Multiple Tasks concurrently​


You can pass a comma-delimited list of targets you wish to trigger to run concurrently.
npx lerna run test,build,lint

If, for example, there are dependencies between your tasks, such as build needing to run before test for particular packages, the task-runner will coordinate that for you as long as you have configured an appropriate Task
Pipeline Configuration.

Run a Task for a single Package​


While developing you rarely run all the builds or all the tests. Instead, you often run things only against the projects you are changing. For instance, you can run the header tests like this:
npx lerna run test --scope=header
Run Tasks Affected by a PR​
You can also run a command for all the projects affected in your PR like this:
npx lerna run test --since=origin/main

Learn more here.

Control How Tasks Run​


For more control over the order tasks are executed, edit the Task Pipeline Configuration.

To speed up your task execution, learn how to Cache Task Results and Distribute Task Execution

Automatic loading of .env files​


By default the modern task runner powered by Nx will automatically load .env files for you. You can set --load-env-files to false if you want to disable this behavior for any reason.

For more details about what .env files will be loaded by default please see: https://nx.dev/recipes/environment-variables/define-environment-variables

Cache Task Results


When it comes to running tasks, caching etc., Lerna and Nx can be used interchangeably. When we say "Lerna can cache builds", we mean that Lerna uses Nx which can cache builds.

It's costly to rebuild and retest the same code over and over again. Lerna uses a computation cache to never rebuild the same code twice.

Setup​
Lerna via Nx has the most sophisticated and battle-tested computation caching system. It knows when the task you are about to run has been executed before, so it can use the cache to restore the results of running that
task.

tip

If you don't have nx.json , run npx lerna add-caching.

To enable caching for build and test, edit the cacheableOperations property in nx.json to include the build and test tasks:

nx.json
{
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": ["build", "test"]
}
}
}
}

info

Note, cacheableOperations need to be side effect free, meaning that given the same input they should always result in the same output. As an example, e2e test runs that hit the backend API cannot be cached as the
backend might influence the result of the test run.

Now, run the following command twice. The second time the operation will be instant:
lerna run build --scope=header

Terminal Output
> lerna run build --scope=header
> header:build [existing outputs match the cache, left as is]
> [email protected] build
> rimraf dist && rollup --config
src/index.tsx → dist...
created dist in 858ms
————————————————————————————————————————————————————————————————
> Lerna (powered by Nx) Successfully ran target test for project header (4ms)
Nx read the output from the cache instead of running the command for 1 out of 1 tasks.

Replaying from Cache​


When Lerna determines that the inputs for a task have not changed, it recreates the outputs of that task as if it actually ran on your machine - but much faster. The outputs of a cached task include both the terminal output
and the files created in the defined output directories for that task.

You can test this out by deleting the dist folder that the header:build task outputs to and then running lerna run build --scope=header again. The cached task will replay instantly and the correct files will be present
in the dist folder.
header/
└── dist/ <-- this folder gets recreated

If your task creates output artifacts in a different location, you can change the output folder(s) that are cached. You can also customize which inputs will invalidate the cache if they are changed.

Advanced Caching​
For a more in-depth understanding of the caching implementation and to fine-tune the caching for your repo, read How Caching Works.

Local Computation Caching​


By default, Lerna (via Nx) uses a local computation cache. Nx stores the cached values only for a week, after which they are deleted. To clear the cache run nx reset , and Nx will create a new one the next time it tries to
access it.

Share Your Cache


The computation cache provided by Lerna can be distributed across multiple machines. You can either build an implementation of the cache or use Nx Cloud. Nx Cloud is an app that provides a fast and zero-config
implementation of distributed caching. It's completely free for OSS projects and for most closed-sourced projects (read more here).

You can connect your workspace to Nx Cloud by running:


npx nx connect-to-nx-cloud

Terminal Output
✔ Enable distributed caching to make your CI faster · Yes
> NX Generating @nrwl/nx-cloud:init
UPDATE nx.json
> NX Distributed caching via Nx Cloud has been enabled
In addition to the caching, Nx Cloud provides config-free distributed execution,
UI for viewing complex runs and GitHub integration. Learn more at https://nx.app
Your workspace is currently unclaimed. Run details from unclaimed workspaces can be viewed on cloud.nx.app by anyone
with the link. Claim your workspace at the following link to restrict access.
https://cloud.nx.app/orgs/workspace-setup?accessToken=YOURACCESSTOKEN

To see the remote cache in action, run:


lerna run build --scope=header && nx reset && lerna run build --scope=header

Terminal Output
> lerna run build --scope=header
> [email protected] build
> rimraf dist && rollup --config
src/index.tsx → dist...
created dist in 786ms
————————————————————————————————————————————————————————————————
> Lerna (powered by Nx) Successfully ran target build for project header (2s)
See logs and investigate cache misses at https://cloud.nx.app/runs/k0HDHACpL8
> NX Resetting the Nx workspace cache and stopping the Nx Daemon.
This might take a few minutes.
> NX Daemon Server - Stopped
> NX Successfully reset the Nx workspace.
> lerna run build --scope=header [remote cache]
> [email protected] build
> rimraf dist && rollup --config
src/index.tsx → dist...
created dist in 786ms
————————————————————————————————————————————————————————————————
> Lerna (powered by Nx) Successfully ran target build for project header (664ms)
Nx read the output from the cache instead of running the command for 1 out of 1 tasks.
Nx Cloud made it possible to reuse header: https://nx.app/runs/P0X6ZGTkqZ

Connecting Your Workspace to Your Nx Cloud Account​


After you have enabled Nx Cloud in your workspace, you will see the following:
> NX NOTE Nx Cloud has been enabled
Your workspace is currently public. Anybody with code access
can view the workspace on nx.app.
You can connect the workspace to your Nx Cloud account at
https://nx.app/orgs/workspace-setup?accessToken=N2Y3NzcyO...
(You can do this later.)

Click on this link to associate the workspace with your Nx Cloud account. If you don't have an Nx Cloud account, you can create one on the spot.

After you claim your workspace, you will be able to manage permissions, create access tokens, set up billing, and so forth.

You will also see an interactive tutorial helping you explore distributed caching and the Nx Cloud user interface.

If you lose this link, you can still connect your workspace to Nx Cloud. Go to nx.app, create an account, and connect your workspace using the access token from nx.json .

Skipping Cloud​
Similar to how --skip-nx-cache will instruct Nx not to use the cache, passing --no-cloud will tell Nx not to use Nx Cloud.

Explore the Project Graph


For Lerna (and Nx) to run tasks quickly and correctly, it creates a graph of the dependencies between all the projects in the repository. Exploring this graph visually can be useful to understand why Lerna is behaving in a
certain way and to get a high level view of your code architecture.

To launch the project graph visualization run:


nx graph

This will open a browser window with an interactive representation of the project graph of your current codebase. Viewing the entire graph can be unmanageable even for smaller repositories, so there are several ways to
narrow the focus of the visualization down to the most useful part of the graph at the moment.

1. Focus on a specific project and then use the proximity and group by folder controls to modify the graph around that project.
2. Use the search bar to find all projects with names that contain a certain string.
3. Manually hide or show projects in the sidebar

Once the graph is displayed, you can click on an individual dependency link to find out what specific file(s) created that dependency.

JSON Project Graph​


If you prefer to analyze the underlying data of the project graph with a script or some other tool, you can run:
nx graph --file=output.json

This will give you all the information that is used to create the project graph visualization.

Distribute Task Execution (DTE)


Lerna speeds up your average CI time with caching and the --since flag. But neither of these features help with the worst case scenario. When something at the core of your repo has been modified and every task needs to
be run in CI, the only way to improve the performance is by adding more agent jobs and efficiently parallelizing the tasks.

The most obvious way to parallelize tasks is to split tasks up by type: running all tests on one job, all builds on another and all lint tasks on a third. This strategy is called binning. This can be made difficult if some test
tasks have build tasks as prerequisites, but assuming you figure out some way to handle that, a typical set up can look like the diagram below. Here the test tasks are delayed until all necessary build artifacts are ready, but
the build and lint tasks can start right away.
CI using binning

The problem with the binning approach is you'll end up with some idle time on one or more jobs. Nx's distributed task execution reduces that idle time to the minimum possible by assigning each individual task to agent
jobs based on the task's average run time. Nx also guarantees that tasks are executed in the correct order and uses distributed caching to make sure that build artifacts from previous tasks are present on every agent job that
needs them.

When you set up Nx's distributed task execution, your task graph will look more like this:

CI using DTE

And not only will CI finish faster, but the debugging experience is the same as if you ran all of your CI on a single job. That's because Nx uses distributed caching to recreate all of the logs and build artifacts on the main
job.

Find more information in this detailed guide to improve your worst case CI times.

Set up​
To distribute your task execution, you need to (1) connect to Nx Cloud and (2) enable DTE in your CI workflow. Each of these steps can be enabled with a single command:

1. Connect to Nx Cloud
nx connect-to-nx-cloud

2. Enable DTE in CI
nx generate @nrwl/workspace:ci-workflow --ci=github

The --ci flag can be github, circleci or azure. For more details on setting up DTE, read this guide.

CI Execution Flow​
Distributed task execution can work on any CI provider. You are responsible for launching jobs in your CI system. Nx Cloud then coordinates the way those jobs work together. There are two different kinds of jobs that
you'll need to create in your CI system.

1. One main job that controls what is going to be executed


2. Multiple agent jobs that actually execute the tasks

The main job execution flow looks like this:


# Coordinate the agents to run the tasks
- npx nx-cloud start-ci-run
# Run any commands you want here
- lerna run lint --since=main & lerna run test --since=main & lerna run build --since=main
# Stop any run away agents
- npx nx-cloud stop-all-agents

The agent job execution flow is very simple:


# Wait for tasks to execute
- npx nx-cloud start-agent

The main job looks more or less the same way as if you haven't used any distribution. The only thing you need to do is to invoke npx nx-cloud start-ci-run at the beginning and optionally invoke npx nx-cloud stop-
all-agents at the end.

The agent jobs run long-running start-agent processes that execute all the tasks associated with a given CI run. The only thing you need to do to set them up is to invoke npx nx-cloud start-agent. This process will
keep running until Nx Cloud tells it to terminate.

Note it's important that the main job and the agent jobs have the same environment and the same source code. They start around the same time. And, once the main job completes, all the agents will be
stopped.

It's also important to note that an Nx Cloud agent isn't a machine but rather a long-running process that runs on a machine. I.e., Nx Cloud doesn't manage your agents--you need to do it in your CI config (check out CI
examples below).

Nx Cloud is an orchestrator. The main job tells Nx Cloud what you want to run, and Nx Cloud will distribute those tasks across the agents. Nx Cloud will automatically move files from one agent to another, from the
agents to the main job.

The end result is that when say lerna run build --since=main completes on the main job, all the file artifacts created on agents are copied over to the main job, as if the main job had built everything locally.

Running Things in Parallel​


--concurrency is propagated to the agents. E.g., npx lerna run build --since=main --concurrency=3 --dte tells Nx Cloud to run up to 3 build targets in parallel on each agent. So if you have say 10 agents, you
will run up to 30 builds in parallel across all of them.

You also want to run as many commands in parallel as you can. For instance,
- lerna run lint --since=main
- lerna run test --since=main
- lerna run build --since=main

is worse than
- lerna run lint --since=main & lerna run test --since=main & lerna run build --since=main

The latter is going to schedule all the three commands at the same time, so if an agent cannot find anything to build, it will start running tests and lints. The result is better agent utilization and shorter CI time.

CI/CD Examples​
The examples below show how to set up CI using Nx and Nx Cloud using distributed task execution and distributed caching.

Every organization manages their CI/CD pipelines differently, so the examples don't cover org-specific aspects of CI/CD (e.g., deployment). They mainly focus on configuring Nx correctly.

Read the guides for more information on how to configure them in CI.

Overview
Azure Pipelines
Circle CI
GitHub Actions
Jenkins

Note that only cacheable operations can be distributed because they have to be replayed on the main job.

Relevant Repositories and Examples​


Nx: On how to make your CI 16 times faster with a small config change
"Lerna & Distributed Task Execution" Example

Version and Publish


Lerna can increment your package's versions as well as publish your packages to NPM, and it provides a variety of options to make sure any workflow can be accommodated.

To show how Lerna does it, we will look at this repository.

If you learn better by doing, clone the repo and follow along.

The repo contains three packages or projects:

header (a library of React components)


footer (a library of React components)
remixapp (an app written using the Remix framework which depends on both header and footer)

We are going to publish the header and the footer packages.

It's common to publish only a subset of the projects. Some projects can be private (e.g., used only for tests), some can be demo apps. In this repo, remixapp isn't "private" in the sense of not wanting people to
see the source files, it is just using the "private": true setting in order to not get published to NPM.

Versioning​
Lerna comes with a version command that allows you to increment your package's version number, commit the changes and tag them accordingly.
lerna version --no-private

you'll get the following output:


lerna notice cli v5.1.2
lerna info current version 1.0.0
lerna info Assuming all packages changed
? Select a new version (currently 1.0.0) (Use arrow keys)
â​¯ Patch (1.0.1)
Minor (1.1.0)
Major (2.0.0)
Prepatch (1.0.1-alpha.0)
Preminor (1.1.0-alpha.0)
Premajor (2.0.0-alpha.0)
Custom Prerelease
Custom Version

info

Note that by passing --no-private we exclude all packages that are marked private in their package.json file.

Lerna detects the current packages, identifies the current version and proposes the next one to choose. Note, you can also pass a semver bump directly like lerna version 1.0.0 . More on the version docs details. Once a
given version is chosen, Lerna updates the package.json with the version number, commits the change, adds a corresponding version tag (e.g. v1.0.0) and pushes the commit and the tag to the remote repository.

packages/footer/package.json
{
"name": "footer",
"version": "1.0.1",
"main": "dist/index.js",
...
}

Note the above operation does not push the package to any NPM repository. If instead we also want Lerna to take care of the publishing process, we can use lerna publish instead.

info

Lerna uses the version property in lerna.json to determine the currently used version

Publishing to NPM​
If we run
lerna publish --no-private
Lerna executes the version incrementing workflow (same as lerna version ) and in addition also pushes the packages to NPM. You should get the following output:

Terminal Output
lerna notice cli v5.1.2
lerna info current version 1.0.0
lerna info Assuming all packages changed
? Select a new version (currently 1.0.0) Patch (1.0.1)
Changes:
- footer: 1.0.0 => 1.0.1
- header: 1.0.0 => 1.0.1
? Are you sure you want to publish these packages? Yes
lerna info execute Skipping releases
lerna info git Pushing tags...
lerna info publish Publishing packages to npm...
...
lerna success published header 1.0.1
...
lerna success published footer 1.0.1
...
Successfully published:
- [email protected]
- [email protected]
lerna success published 2 packages

from-package​
Another way Lerna can determine which packages to publish is with from-package . Lerna will compare the version of every package in the repository with the version of it that is published to npm. For each package that
has a version that is greater than the published version, Lerna will publish that package to npm.

This mode does not explicitly require that the packages have been versioned with lerna version , which makes it great for workspaces that have their own versioning scripts.
lerna publish from-package

info

Lerna always uses npm to publish packages. If you use a package manager other than npm, you will need to still add the appropriate publishing configuration to .npmrc, even if npmClient is set to something other than npm
in lerna.json.

Versioning strategies​
Lerna allows you to manage your project using one of two modes: Fixed or Independent.

Fixed/Locked mode (default)​


Fixed mode Lerna projects operate on a single version line. The version is kept in the lerna.json file at the root of your project under the version key. When you run lerna publish , if a package has been updated since
the last time a release was made, it will be updated to the new version you're releasing. This means that you only publish a new version of a package when you need to.

Note: If you have a major version zero, all updates are considered breaking. Because of that, running lerna publish with a major version zero and choosing any non-prerelease version number will cause new
versions to be published for all packages, even if not all packages have changed since the last release.

Use this if you want to automatically tie all package versions together. One issue with this approach is that a major change in any package will result in all packages having a new major version.

Synchronized Versions​

Lerna will only version and publish packages that have changed since the previous release, causing package versions to drift apart over time. To prevent this, use the --force-publish option with lerna version . This
will force Lerna to always version all packages, regardless of if they have changed since the previous release. Then they will all be published to the registry by lerna publish from-git . As a result, all package versions
will stay synchronized to the version in lerna.json.

Independent mode​
npx lerna init --independent

Independent mode Lerna projects allows maintainers to increment package versions independently of each other. Each time you publish, you will get a prompt for each package that has changed to specify if it's a patch,
minor, major or custom change.

Independent mode allows you to more specifically update versions for each package and makes sense for a group of components. Combining this mode with something like semantic-release would make it less painful.
(There is work on this already at atlassian/lerna-semantic-release).

Set the version key in lerna.json to independent to run in independent mode.

Editor Integrations
Nx Console displays the npm scripts for all your projects in the VS Code sidebar and allows you to run them with a single click or open the script definition in your editor.

Download​
VSCode​
If you are using VSCode, you can install the Nx Console VSCode Plugin from Marketplace. The Nx Console VSCode Plugin is built and maintained by the Nx team.

WebStorm​
If you are using WebStorm, you can install one of the available plugins:

nx-webstorm
Nx Console Idea

These plugins are NOT built or maintained by the Nx team. They are maintained by independent community contributors.

Nx Console for VSCode​

Install from the VSCode Marketplace


Contribute on GitHub

Workspace Watching
note

Workspace Watching is available as of Lerna 6.4.0.

Lerna can watch for file changes within packages and automatically execute commands from the root of the repository. This is useful if you need to rebuild packages or rerun tests as you update files during your
development workflow.
This replaces the need to manually set up watching for each package individually.

Examples​
Watch all packages and echo the package name and the files that changed:
$ lerna watch -- echo \$LERNA_PACKAGE_NAME \$LERNA_FILE_CHANGES

Watch all packages and run the "build" script on a package when a file within it changes:
$ lerna watch -- lerna run build --scope=\$LERNA_PACKAGE_NAME

Watch all packages and run the "build" script on everything affected by the changes:
$ lerna watch -- lerna run build --since

Watch a single package and run the "build" script on it when a file within it changes:
$ lerna watch --scope="my-package-1" -- lerna run build --scope=\$LERNA_PACKAGE_NAME

Watch a single package and its dependencies, running the "build" script on any of them that change:
$ lerna watch --scope="my-package-1" --include-dependencies -- lerna run build --scope=\$LERNA_PACKAGE_NAME

Watch all packages and run the build script for the package that changed and all packages that depend on it:
$ lerna watch -- lerna run build --scope=\$LERNA_PACKAGE_NAME --include-dependents

For more advanced filtering, see the filter options documentation. For more available options, see the lerna watch documentation.

Watch Environment Variables​


Lerna will set the environment variables $LERNA_PACKAGE_NAME and $LERNA_FILE_CHANGES when running the inner command. These can be used to customize the command that is run.

$LERNA_PACKAGE_NAME will be replaced with the name of the package that changed.
$LERNA_FILE_CHANGES will be replaced with the file(s) that changed. If multiple file changes are detected in one cycle, then $LERNA_FILE_CHANGES will list them all, separated by spaces.

note

When using $LERNA_PACKAGE_NAME and $LERNA_FILE_CHANGES, you will need to escape the $ with a backslash (\). See the examples above.

Running With Package Managers​


The examples above showcase using lerna directly in the terminal. However, you can also use lerna via a package manager without adding it to your path:

pnpm:
pnpm lerna watch -- lerna run build --scope=\$LERNA_PACKAGE_NAME

yarn:
yarn lerna -- watch -- lerna run build --scope=\$LERNA_PACKAGE_NAME

npx:
npx -c 'lerna watch -- lerna run build --scope=\$LERNA_PACKAGE_NAME'

note

When using npx, you will need to use -c and surround the entire lerna watch command in single quotes ('). Without this, npx will try to replace the watch environment variables before passing the command to lerna,
resulting in an always empty value for $LERNA_PACKAGE_NAME and $LERNA_FILE_CHANGES.

None

Task Pipeline Configuration


Lerna delegates the running of npm scripts (forking processes etc) to Nx. The nx.json file is the place where you can configure how Nx does it.

tip

If you don't have nx.json , run npx lerna add-caching.

Run Tasks in Parallel​


If you want to increase the number of processes running the scripts to, say, 5 (by default, it is 3), pass the following:
npx lerna run build --concurrency=5

Note, you can also change the default in nx.json , like this:

nx.json
{
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": [],
"parallel": 5
}
}
}
}

Define Task Dependencies (aka Task Pipelines)​


Without our help Lerna cannot know what targets (scripts) have prerequisites and which ones don't. You can define task dependencies in the nx.json file:

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

With this, Lerna knows that before it can build a project, it needs to build all of its dependencies first. There are, however, no constraints on tests.

Once you define the targetDefaults property the sort flag is ignored.

This mechanism is very flexible. Let's look at this example:

nx.json
{
...
"targetDefaults": {
"build": {
"dependsOn": ["^build", "prebuild"]
},
"test": {
"dependsOn": ["build"]
}
}
}

Note, older versions of Nx used targetDependencies instead of targetDefaults. Both still work, but targetDefaults is recommended.

The ^ symbol (a.k.a the caret symbol) simply means dependencies. Therefore whereas "test": { "dependsOn": ["build"] } means a particular project's "test" target depends on its own "build" target to have already
completed before running, "build": { "dependsOn": ["^build"] } means that a particular project's "build" target depends on the "build" target of all of the project's dependencies to have already completed before
running.

When running lerna run test --scope=myproj , the above configuration would tell Lerna to

1. Run the test command for myproj


2. But since there's a dependency defined from test -> build , Lerna runs build for myproj first.
3. build itself defines a dependency on prebuild (on the same project) as well as build of all the dependencies. Therefore, it will run the prebuild script and will run the build script for all the dependencies.

Note, Lerna doesn't have to run all builds before it starts running tests. The task orchestrator will run as many tasks in parallel as possible as long as the constraints are met.

Situations like this are pretty common:

Mixing Targets

Because we described the rules in nx.json , they will apply to all the projects in the repo. You can also define project-specific rules by adding them the project's package.json .
{
...
"nx": {
"targets": {
"test": {
"dependsOn": [
"build"
]
}
}
}
}

How Caching Works


Before running any task, Lerna computes its computation hash. As long as the computation hash is the same, the output of running the task is the same.

By default, the computation hash for - say - lerna run test --scope=remixapp includes:

All the source files of remixapp and its dependencies


Relevant global configuration
Versions of external dependencies
Runtime values provisioned by the user such as the version of Node
CLI Command flags
computation-hashing

This behavior is customizable. For instance, lint checks may only depend on the source code of the project and global configs. Builds can depend on the dts files of the compiled libs instead of their source.

After Lerna computes the hash for a task, it then checks if it ran this exact computation before. First, it checks locally, and then if it is missing, and if a remote cache is configured, it checks remotely.

If Lerna finds the computation, Lerna retrieves it and replays it. Lerna places the right files in the right folders and prints the terminal output. From the user’s point of view, the command ran the same, just a lot faster.
cache

If Lerna doesn’t find a corresponding computation hash, Lerna runs the task, and after it completes, it takes the outputs and the terminal logs and stores them locally (and if configured remotely as well). All of this
happens transparently, so you don’t have to worry about it.

Although conceptually this is fairly straightforward, Lerna optimizes this to make this experience good for you. For instance, Lerna:

Captures stdout and stderr to make sure the replayed output looks the same, including on Windows.
Minimizes the IO by remembering what files are replayed where.
Only shows relevant output when processing a large task graph.
Provides affordances for troubleshooting cache misses. And many other optimizations.

As your workspace grows, the task graph looks more like this:

cache

All of these optimizations are crucial for making Lerna usable for any non-trivial workspace. Only the minimum amount of work happens. The rest is either left as is or restored from the cache.

Source Code Hash Inputs​


The result of building/testing an application or a library depends on the source code of that project and all the source codes of all the libraries it depends on (directly or indirectly).

By default, Lerna is conservative. When running, say, lerna run test --scope=remixapp Lerna will consider all the files in the remixapp directory and all the files in the header and footer directories (remixapp
dependencies). This would result in unnecessary cache misses. For instance, we know that changing a footer's spec file will not change the result of the test command above.

We can define a more precise configuration as follows:

NOTE: "{projectRoot}" and "{workspaceRoot}" are special syntax supported by the task-runner, which will be appropriately interpolated internally when the command runs. You should therefore not replace
"{projectRoot}" or "{workspaceRoot}" with fixed paths as this makes your configuration less flexible.

nx.json
{
"namedInputs": {
"default": ["{projectRoot}/**/*"],
"prod": ["!{projectRoot}/**/*.spec.tsx"]
},
"targetDefaults": {
"build": {
"inputs": ["prod", "^prod"]
},
"test": {
"inputs": ["default", "^prod", "{workspaceRoot}/jest.config.ts"]
}
}
}

With this configuration, the build script will only consider the non-test files of remixapp, header and footer. The test script will consider all the source files for the project under test and only non-test files of its
dependencies. The test script will also consider the jest config file at the root of the workspace.

Runtime Hash Inputs​


Your targets can also depend on runtime values.

nx.json
{
"targetDefaults": {
"build": {
"inputs": [{ "env": "MY_ENV_NAME" }, { "runtime": "node -v" }]
}
}
}
Args Hash Inputs​
Finally, in addition to Source Code Hash Inputs and Runtime Hash Inputs, Lerna needs to consider the arguments: For example, lerna run build --scope=remixapp and lerna run build --scope=remixapp -- --
flag=true produce different results.

Note, only the flags passed to the npm scripts itself affect results of the computation. For instance, the following commands are identical from the caching perspective.
npx lerna run build --scope=remixapp
npx lerna run build --ignore=header,footer

In other words, Lerna does not cache what the developer types into the terminal.

If you build/test/lint… multiple projects, each individual build has its own hash value and will either be retrieved from cache or run. This means that from the caching point of view, the following command:
npx lerna run build --scope=header,footer

is identical to the following two commands:


npx lerna run build --scope=header
npx lerna run build --scope=footer

What is Cached​
Lerna works on the process level. Regardless of the tools used to build/test/lint/etc.. your project, the results are cached.

Lerna sets up hooks to collect stdout/stderr before running the command. All the output is cached and then replayed during a cache hit.

Lerna also caches the files generated by a command. The list of files/folders is listed in the outputs property of the project's package.json :

NOTE: "{projectRoot}" and "{workspaceRoot}" are special syntax supported by the task-runner, which will be appropriately interpolated internally when the command runs. You should therefore not replace
"{projectRoot}" or "{workspaceRoot}" with fixed paths as this makes your configuration less flexible.

E.g. packages/my-project/package.json
{
"nx": {
"targets": {
"build": {
"outputs": ["{projectRoot}/build", "{projectRoot}/public/build"]
}
}
}
}

If the outputs property for a given target isn't defined in the project' s package.json file, Lerna will look at the targetDefaults section of nx.json :

nx.json
{
...
"targetDefaults": {
"build": {
"dependsOn": [
"^build"
],
"outputs": [
"{projectRoot}/dist",
"{projectRoot}/build",
"{projectRoot}/public/build"
]
}
}
}

If neither is defined, Lerna defaults to caching dist and build at the root of the repository.

Skipping Cache​
Sometimes you want to skip the cache. If, for example, you are measuring the performance of a command, you can use the --skip-nx-cache flag to skip checking the computation cache.
npx lerna run build --skip-nx-cache
npx lerna run test --skip-nx-cache

Customizing the Cache Location​


The cache is stored in node_modules/.cache/nx by default. To change the cache location, update the cacheDirectory option for the task runner in nx.json :
{
"tasksRunnerOptions": {
"default": {
"options": {
"cacheableOperations": ["build", "test"],
"cacheDirectory": "/tmp/mycache"
}
}
}
}

Distributed Task Execution Guide


The illustrations in this guide are created by Nrwlian Nicole Oliver
how does distributed task execution work in Nx Cloud?

What's a Task?​

A task, from Lerna's perspective, is a target running on a project. i.e. The target test running on the project shared-product-ui is a task. For more information about tasks, see the Run Tasks article.

Nx Cloud Schedules Your CI Tasks Automatically​

Let's imagine for every PR in CI, you want to lint, test and build all affected projects. When you write your CI workflow, you have no way of knowing how many projects will be affected by each PR or how long each task
will take. No matter how carefully you set things up, there will be wasted time if you manually assign a static number of agent machines for linting, testing and building. This approach is called binning.

Luckily, with distributed task execution, Nx Cloud can dynamically assign tasks to agents as they become available.

Nx Cloud Efficiently Orchestrates Agents​


Nx will automatically schedule tasks w/agents you assign in CI.

When you set up DTE, you define (1) the tasks that you want to run and (2) the number of agents that are available for Nx Cloud to use. Then the Nx Cloud orchestrator distributes tasks to agents efficiently - so that all the
agents are being fully utilized and your CI process finishes as soon as possible.
Task Execution Order Matters​

There are some tasks that need to be executed before other tasks, but Nx Cloud takes that into account when it assigns tasks to agents. For a more detailed look at defining those dependencies, read the Run Tasks article.

Why Distribute Tasks?​


Result: Faster Builds!

Efficiently parallelizing your CI process across many agents can dramatically speed up your CI, which helps developers identify problems faster and get more work done.

What Does It Cost?​


Nx Cloud is FREE for open source projects. Contact [email protected] to get set up.

For closed source projects, the first 500 computation hours per month are free. Most workspaces don't exceed this amount. No credit card is required. After 500 hours, the cost is $1 per computation hour.

For more details, see the Nx Cloud pricing page.

Security​
Your actual code is not stored in the cloud, but the hashed inputs and cached results of your tasks are. It is possible to enable end to end encryption of that data so that no one can view that information without your key.
Also, if you want to host Nx Cloud on your own servers, you can sign up for Nx Private Cloud.

Example​
This is an example repo showing how easy it is to set up distributed task execution, showing the performance gains, and comparing to sharding/binning.

Illustration​
Here is the full illustrated explanation page that Nicole Oliver made:

How Does DTE Work Explainer


Configuring Published Files
When publishing a package to a registry, the default is to publish everything in the package's source directory. This is not always optimal, since there are often files only relevant for development, such as tests and
configuration files, and it could be that you first compile your source files and output them to a centralized location in a monorepo setup.

Lerna provides a number of configuration options to ensure that only the appropriate files are packed and published to a registry.
"files" and .gitignore​
Lerna always publishes using npm's tooling, and it has a few built in ways to include or exclude files. The easiest way to configure which files are included in the published package are via the "files" property in
package.json and .gitignore. See the npm documentation for more information on how npm recognizes files for publishing.

--contents [legacy -> prefer --directory]​


A number of commands, including lerna publish , support a generalized --contents option, which sets the directory to publish for ALL packages.

This is only useful for publishing if the packages in your monorepo have a simplistic, uniform output structure. The argument passed to --contents must be a subdirectory that exists within every package being published.
See the lerna publish documentation for details.

In v7, we introduced a more powerful, more focused --directory option for lerna publish . Please prefer that over the --contents option, which will likely be deprecated in future.

--directory​
In v7, we introduced a more powerful, more focused --directory option for lerna publish .

It can be configured in your lerna.json and supports using the following dynamic placeholders: {workspaceRoot}, {projectRoot}, {projectName}. These values will be dynamically replaced at publish time.

This means you can now succinctly express setups which are uniform in terms of their style, but not literally identical across all packages.

For example, let's say we have a monorepo where we build all packages and their outputs are set to go to a centralized location (as is common in Nx workspaces, for example):

We have packages/package-a which writes its build output to dist/packages/package-a , and packages/package-b which writes its build output to dist/packages/package-b .

Even though the paths are strictly different, we have a consistent approach we can now express using the placeholders:
{workspaceRoot}/dist/{projectRoot}

{workspaceRoot} will be replaced by the absolute path to our lerna repo, and {projectRoot} will be replace by packages/package-a in the case of package-a, and packages/package-b in the case of package-b.

The way we apply that in the lerna.json is as follows:


// lerna.json
{
"version": "1.0.0",
"command": {
"publish": {
"directory": "{workspaceRoot}/dist/{projectRoot}"
}
}
}

You can also set or override the publish directory option within a package's package.json , if you need to something completely custom for that particular package.

An example configuration for a package that publishes from a dist/packages/foo folder in the root of the repo:
// packages/foo/package.json
{
"name": "foo",
"version": "1.0.0",
"lerna": {
"command": {
"publish": {
"directory": "../../dist/packages/foo"
}
}
}
}

info

You will need to make sure that your custom directory location contains a valid package.json which will be used for the registry publish. You could create this via a lifecycle script such as prepare , prepublishOnly, or
prepack if you need more complex custom logic involved, or simply have it copied for you from the package's source automatically by configuring it as an asset. See the upcoming section on Including Additional Assets
in Published Packages for full details.

If you wanted to make one of your packages behave like a standard lerna package and publish from source, you could override its publish config like so:
// packages/foo/package.json
{
"name": "foo",
"version": "1.0.0",
"lerna": {
"command": {
"publish": {
"directory": "."
}
}
}
}

Including Additional Assets in Published Packages


Lerna can copy files from your source directory to the directory specified for publishing. Just as with the directory option, this can be configured in the lerna.json (including using dynamic placeholders within asset
definitions), or within the package.json of a particular package.

Regardless of which file it is configured in, the "assets" property should be an array of glob patterns or objects with a "from" and "to" property. The "from" property should be a specific file or glob pattern that matches
files in the source directory, and the "to" property is the path to copy the file to within the publish directory.

This example package builds its output to a root dist/packages/bar directory. Lerna is configured to copy additional files to this directory, then publish the contents of dist/packages/bar to npm.
// packages/bar/package.json
{
"name": "bar",
"version": "1.0.0",
"lerna": {
"command": {
"publish": {
"directory": "../../dist/packages/bar",
"assets": [
"README.md",
"package.json",
"docs/*.md",
{
"from": "static/images/*",
"to": "assets"
},
{
"from": "../../CONTRIBUTING.md",
"to": "./"
}
]
}
}
}
}
Lerna will consume the above configuration and copy the appropriate files to the dist directory, producing a structure like this:
dist/packages/bar
├── assets
│ ├── my-image-1.png
│ └── my-image-2.png
├── CONTRIBUTING.md
├── docs
│ ├── my-doc-1.md
│ └── my-doc-2.md
├── package.json
└── README.md

Using pnpm with Lerna


Lerna can be used in a pnpm workspace to get the full benefits of both pnpm and Lerna.

When used in a pnpm workspace, Lerna will:

resolve package locations with pnpm-workspace.yaml (https://pnpm.io/workspaces)


enforce useWorkspaces: true in lerna.json (and ignore packages: in package.json ).
block usage of bootstrap, link, and add commands. Instead, you should use pnpm commands directly to manage dependencies (https://pnpm.io/cli/install).
respect the workspace protocol for package dependencies.
During lerna version , dependencies will be updated as normal, but will preserve the workspace: prefix if it exists.
If a workspace alias is used, then lerna version will not bump the version of the dependency, since aliases don't specify a version number to bump.

Getting Started​
To set up pnpm with Lerna:

1. If not installed already, install pnpm: https://pnpm.io/installation.

2. Remove the node_modules/ folder in the root, if it exists. If not already using workspaces, run lerna clean to remove the node_modules/ folder in all packages.

3. Set "npmClient": "pnpm" in lerna.json.

4. Create a pnpm-workspace.yaml file in the root of your project. If you are already using npm or yarn workspaces, move the "workspaces" property from package.json to pnpm-workspace.yaml. If you were not
already using workspaces, move the "packages" property from lerna.json to pnpm-workspace.yaml. For example:

package.json
{
"workspaces": ["packages/*"]
}

and

lerna.json
{
"packages": ["packages/*"]
}

become:

pnpm-workspace.yaml
packages:
- "packages/*"

5. (optional) Run pnpm import to generate a pnpm-lock.yaml file from an existing lockfile. See https://pnpm.io/cli/import for supported lockfile sources.

6. Run pnpm install .

Commands
lerna add-caching
lerna changed
lerna clean
lerna create
lerna diff
lerna exec
lerna import
lerna info
lerna init
lerna list
lerna publish
lerna repair
lerna run
lerna version
lerna watch

Filter Options​
Lerna commands can have filter options applied to control which packages they operate on.

Options for lerna sub-commands that need filtering

Install lerna for access to the lerna CLI.

Options​
--scope <glob>​

Include only packages with names matching the given glob.


$ lerna exec --scope my-component -- ls -la
$ lerna run --scope "toolbar-*" test
$ lerna run --scope package-1 --scope "*-2" lint

Note: For certain globs, it may be necessary to quote the option argument to avoid premature shell expansion.

Running with npx​


When running lerna with npx, it is necessary to use an explicit "=" when passing glob arguments. This is to prevent npx from prematurely expanding the arguments.

For example:
$ npx lerna run --scope="toolbar-*" test
$ npx lerna run --scope="package-{1,2,5}" test

--ignore <glob>​

Exclude packages with names matching the given glob.


$ lerna exec --ignore "package-{1,2,5}" -- ls -la
$ lerna run --ignore package-1 test
$ lerna run --ignore "package-@(1|2)" --ignore package-3 lint

More examples of filtering can be found here.

--no-private​

Exclude private packages. They are included by default.

--since [ref]​

Only include packages that have been changed since the specified ref. If no ref is passed, it defaults to the most-recent tag.
# List the contents of packages that have changed since the latest tag
$ lerna exec --since -- ls -la
# Run the tests for all packages that have changed since `main`
$ lerna run test --since main
# List all packages that have changed since `some-branch`
$ lerna ls --since some-branch

This can be particularly useful when used in CI, if you can obtain the target branch a PR will be going into, because you can use that as the ref to the --since option. This works well for PRs going into the default
branch as well as feature branches.

--exclude-dependents​

Exclude all transitive dependents when running a command with --since , overriding the default "changed" algorithm.

This flag has no effect without --since , and will throw an error in that case.

--include-dependents​

Include all transitive dependents when running a command regardless of --scope , --ignore , or --since .

--include-dependencies​

Include all transitive dependencies when running a command regardless of --scope , --ignore , or --since .

Used in combination with any command that accepts --scope (bootstrap, clean, ls, run, exec). Ensures that all dependencies (and dev dependencies) of any scoped packages (either through --scope or --ignore ) are
operated on as well.

Note: This will override the --scope and --ignore flags.

i.e. A package matched by the --ignore flag will still be bootstrapped if it is depended on by another package that is being bootstrapped.

This is useful for situations where you want to "set up" a single package that relies on other packages being set up.
$ lerna bootstrap --scope my-component --include-dependencies
# my-component and all of its dependencies will be bootstrapped

$ lerna bootstrap --scope "package-*" --ignore "package-util-*" --include-dependencies


# all packages matching "package-util-*" will be ignored unless they are
# depended upon by a package whose name matches "package-*"

--include-merged-tags​

$ lerna exec --since --include-merged-tags -- ls -la

Include tags from merged branches when running a command with --since . This is only useful if you do a lot of publishing from feature branches, which is not generally recommended.

Limitations​
Even though you can run Lerna without installing the project dependencies first, for instance with pnpm dlx or npx, it is not recommended. The command may work, but its output may not be 100% accurate. See this issue
for more details.

Configuration
Lerna's configuration is split into two files: lerna.json and nx.json .

Lerna.json
npmClient​
It is important to set this value if you are not using npm as your package manager (e.g. if you are using yarn or pnpm) so that lerna can adjust some of its internal logic when resolving configuration and packages. This is
particularly true in the case of pnpm because it uses a separate pnpm-workspaces.yaml file to define its workspaces configuration.

packages​
By default, lerna will try and reuse any workspaces configuration you may have from your package manager of choice. If you prefer to specify a subset of your available packages for lerna to operate on, you can use the
packages property which will tell Lerna where to look for package.json files.

lerna.json
{
"packages": ["packages/*"]
}

version​
Lerna has two modes of publishing packages: fixed and independent. When using the fixed mode, all the affected packages will be published using the same version. The last published version is recorded in lerna.json
as follows:

lerna.json
{
"version": "1.2.0"
}

When using the independent mode, every package is versioned separately, and lerna.json will look as follows:

lerna.json
{
"version": "independent"
}

See the version and publish docs for more details.

commands​
The lerna.json files can also encode options for each command like so:
{
"command": {
"version": {
"allowBranch": "main",
"conventionalCommits": true
}
}
}

Find the available options in the API docs.

Nx.json
NOTE: "{projectRoot}" and "{workspaceRoot}" are special syntax supported by the task-runner, which will be appropriately interpolated internally when the command runs. You should therefore not replace
"{projectRoot}" or "{workspaceRoot}" with fixed paths as this makes your configuration less flexible.

nx.json
{
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": ["build", "test"]
}
}
},
"namedInputs": {
"default": ["{projectRoot}/**/*"],
"prod": ["!{projectRoot}/**/*.spec.tsx"]
},
"targetDefaults": {
"build": {
"dependsOn": ["prebuild", "^build"],
"inputs": ["prod", "^prod"],
"outputs": ["{projectRoot}/dist"]
},
"test": {
"inputs": ["default", "^prod", "{workspaceRoot}/jest.config.ts"]
}
}
}

taskRunnerOptions​
runner​
Everything in Nx is customizable, including running npm scripts. Most of the time you will either use the default runner or the @nrwl/nx-cloud runner.

cacheableOperations​
The cacheableOperations array defines the list of npm scripts/operations that are cached by Nx. In most repos all non-long running tasks (i.e., not serve) should be cacheable.

Target Defaults​
Targets are npm script names. You can add metadata associated with say the build script of each project in the repo in the targetDefaults section.

dependsOn​
Targets can depend on other targets. A common scenario is having to build dependencies of a project first before building the project. The dependsOn property can be used to define the dependencies of an individual target.

"dependsOn": [ "prebuild", "^build"] tells Nx that every build script requires the prebuild script of the same project and the build script of all the dependencies to run first.

inputs & namedInputs​


The inputs array tells Nx what to consider to determine whether a particular invocation of a script should be a cache hit or not. There are three types of inputs:

Filesets

Examples:

{projectRoot}/**.*.ts
same as {fileset: "{projectRoot}/**/*.ts"}
{workspaceRoot}/jest.config.ts
same as {fileset: "{workspaceRoot}/jest.config.ts}

Runtime Inputs

Examples:

{runtime: "node -v"}

Node the result value is hashed, so it is never displayed.

Env Variables

Examples:

{env: "MY_ENV_VAR"}

Node the result value is hashed, so it is never displayed.

Named Inputs

Examples:
inputs: ["prod"]
same as inputs: [{input: "prod", projects: "self"}]

Often the same glob will appear in many places (e.g., prod fileset will exclude spec files for all projects).. Because keeping them in sync is error-prone, we recommend defining named inputs, which you can then reference
in all of those places.

Using ^​

Examples:

inputs: ["^prod"]
same as inputs: [{input: "prod", projects: "dependencies"}]

Similar to dependsOn, the "^" symbols means "dependencies". This is a very important idea, so let's illustrate it with an example.
"test": {
"inputs": [ "default", "^prod" ]
}

The configuration above means that the test target depends on all source files of a given project and only prod sources (non-test sources) of its dependencies. In other words, it treats test sources as private. If your remixapp
project depends on the header library, changing the header tests will not have any effect on the remixapp test target.

outputs​
"outputs": ["{projectRoot}/dist"] tells Nx where the build script is going to create file artifacts. The provided value is actually the default, so we can omit it in this case. "outputs": [] tells Nx that the test target
doesn't create any artifacts on disk. You can list as many outputs as you many. You can also use globs or individual files as outputs.

This configuration is usually not needed. Nx comes with reasonable defaults which implement the configuration above.

Project-Specific Configuration​
For a lot of workspaces, where projects are similar, nx.json will contain the whole Nx configuration. Sometimes, it's useful to have a project-specific configuration, which is placed in the project's package.json file.

package.json
{
"name": "parent",
"scripts": {
"build": "...",
"test": "..."
},
"dependencies": {...},
"nx": {
"namedInputs": {
"prod": [
"!{projectRoot}/**/*.test.tsx",
"{workspaceRoot}/configs/webpack.conf.js"
]
},
"targets": {
"build": {
"dependsOn": [
"^build"
],
"inputs": [
"prod",
"^prod"
],
"outputs": [
"{workspaceRoot}/dist/parent"
]
}
}
"implicitDependencies": ["projecta", "!projectb"]
}
}

Note, the namedInputs and targetDefaults defined in nx.json are simply defaults. If you take that configuration and copy it into every project's package.json file, the results will be the same.

In other words, every project has a set of named inputs, and it's defined as: {...namedInputsFromNxJson, ...namedInputsFromProjectsPackageJson}. Every target/script's dependsOn is defined as
dependsOnFromProjectsPackageJson || dependsOnFromNxJson . The same applies to inputs and outputs .

inputs & namedInputs​


Defining inputs for a given target would replace the set of inputs for that target name defined in nx.json . Using pseudocode inputs = packageJson.targets.build.inputs ||
nxJson.targetDefaults.build.inputs.

You can also define and redefine named inputs. This enables one key use case, where your nx.json can define things like this (which applies to every project):
"test": {
"inputs": [
"default",
"^prod"
]
}

And projects can define their prod fileset, without having to redefine the inputs for the test target.

package.json
{
"name": "parent",
"scripts": {
"build": "...",
"test": "..."
},
"dependencies": {...},
"nx": {
"namedInputs": {
"prod": [
"!{projectRoot}/**/*.test.js",
"{workspacRoot}/jest.config.js"
]
}
}
}

In this case Nx will use the right prod input for each project.

dependsOn​
Defining dependsOn for a given target would replace dependsOn for that target name defined in nx.json . Using pseudocode dependsOn = packageJson.targets.build.dependsOn ||
nxJson.targetDefaults.build.dependsOn.

outputs​
Defining outputs for a given target would replace outputs for that target name defined in nx.json . Using pseudocode outputs = packageJson.targets.build.outputs || nxJson.targetDefaults.build.outputs .
implicitDependencies​
The "implicitDependencies": ["projecta", "!projectb"] line tells Nx that the parent project depends on projecta even though there is no dependency in its package.json . Nx will treat such a dependency in the
same way it treats explicit dependencies. It also tells Nx that even though there is an explicit dependency on projectb, it should be ignored.

Utilities
Lerna ships some utility functions that can be used in creating your own tools within a Lerna monorepo.
const utils = require("lerna/utils");

detectProjects()​
The detectProjects() function creates the same project graph file mapping that Lerna uses under the covers to execute its commands. This is useful for writing your own scripts that need to operate on the same set of
packages that Lerna would.
const { detectProjects } = require("lerna/utils");
const { projectGraph, projectFileMap } = await detectProjects();

The projectGraph that is returned will be a ProjectGraphWithPackages, which is an extension of the ProjectGraph type from @nx/devkit. It contains additional metadata about projects that have package.json files. It
also has a localPackageDependencies property that tracks internal npm dependencies between projects (as opposed to external npm dependencies that are downloaded from the registry).

The projectFileMap is a mapping of project names to the files within them. This is used to determine which project needs to be versioned when a file changes.

See Lerna's TypeScript source code for specific type details.

Lerna and Nx Versions


The latest version of Lerna is kept up to date with the latest major version of Nx in order to support the latest features. If you have an older version of Lerna or Nx, you can use the table below to ensure compatibility
between the two.

Lerna and Nx Version Compatibility Matrix​


Below is a reference table that matches versions of Lerna to the version of Nx that is compatible with it.

We provide a recommended version, and it is usually the latest minor version of Nx in the range provided because there will have been bug fixes added since the first release in the range.

Lerna Version Nx Version (recommended) Nx Version (range)


>=7.1.4 <= latest latest >=16.5.1 <= latest
>= 7.0.0 < 7.1.4 latest >=16.3.1 <= latest
>= 6.5.0 < 7.0.0 15.9.4 >=15.5.2 < 16
>= 6.4.0 < 6.5.0 15.9.4 >=15.4.2 < 16
>= 6.0.1 < 6.4.0 15.9.4 >=14.8.6 < 16
>= 5.6.0 < 6.0.1 15.9.4 >=14.8.1 < 16
>=5.5.0 < 5.6.0 15.9.4 >=14.6.1 < 16
>=5.4.0 < 5.5.0 15.9.4 >=14.5.4 < 16
>= 5.2.0 < 5.4.0 15.9.4 >=14.4.3 < 16
< 5.2.0 N/A* N/A*

*Lerna does not depend on Nx before version 5.2.0

Legacy Package Management

Migrating from lerna bootstrap, lerna add and lerna link in lerna v7 and later​
In lerna v7.0.0, we removed the lerna bootstrap, lerna add and lerna link commands in lerna by default.

This section covers how best to migrate away from using them and modernize your setup using package manager workspaces. For full context on why this necessary, see Background below.

The important mental shift is to recognize that lerna is not responsible for installing and linking your dependencies in your repo, your package manager is much better suited to that task.

The way to achieve this is by using your package manager's workspaces feature. See their respective documentation here:

npm (https://docs.npmjs.com/cli/using-npm/workspaces)
yarn (https://yarnpkg.com/features/workspaces)
pnpm (https://pnpm.io/workspaces)

By using workspaces, your package manager will perform the same exact linking that lerna bootstrap and lerna link were doing for you before, except it is baked right into the install command. No additional
commands after running an install are necessary (as long as you have workspaces configured per the package manager documentation above).

The same thing goes for replacing lerna add. Adding and removing dependencies is something your package manager already does for you, and because workspaces is a first class use case, you can run an appropriate
install command to add a dependency to a specific package/workspace and, again, all the relevant local linking will take place automatically.

See below for more concrete comparisons, and before and after usage.

Replacing your usage of lerna bootstrap/lerna link​

What does it do?​

lerna bootstrap was used in place of npm install (or yarn/pnpm). It would install all external packages and link all internal packages within the workspace. lerna link would just perform the internal linking step of
this operation.
Where would I find it?​

It would most likely be in the "scripts" property of package.json in the root of your workspace. Also check your CI pipelines, as they might also be calling lerna bootstrap in place of npm install (or yarn/pnpm).

What do I replace it with?​

Replace lerna bootstrap with npm install (or yarn/pnpm). If you are already performing your package manager's install command somewhere in your workflow before where you had previously called lerna
bootstrap, then you can just delete it instead. lerna link can just be removed, as the linking step is now handled by your package manager during npm install.

info

If you are using yarn and depend on linking binaries, then you may need to delete your node_modules folder once after switching to workspaces. For details, see this yarn issue.

Replacing your usage of lerna add​

What does it do?​

lerna add was used to add a dependency to packages in the workspace. It would update the package.json files of each package to add the dependency.

Where would I find it?​

Though usually called manually, lerna add might be found in some scripts in package.json in the root of your workspace.

What do I replace it with?​

lerna add can mostly be replaced with a variation of npm install (or yarn/pnpm). The most common use case for lerna add was to add a single dependency to a single package within the workspace. This command
looks like:
lerna add <dependency> --scope <package>

and can be replaced directly with:


npm install <dependency> -w <package>

The -w flag tells npm to only install the dependency in the workspace package specified by <package>, similar to the --scope option for Lerna.

If you need to add a dependency to multiple packages, you can use the -w option multiple times:
npm install <dependency> -w <package1> -w <package2>

Custom Hoisting​
One of the nice things about lerna's legacy bootstrap command was the control it offered you around hoisting or not hoisting certain dependencies up to the root of the repo, or leaving them in nested locations.

Therefore you may be concerned about migrating away from lerna bootstrap if you have quite a custom setup in terms of package hoisting.

In our experience of testing out the various package managers, we have found that modern yarn (i.e. v3 and later) offers the most flexibility in terms of hoisting controls:

https://yarnpkg.com/configuration/yarnrc/#nmHoistingLimits

We have yet to find a lerna bootstrap powered repo, no matter the hoisting complexities, that could not be converted to modern yarn, so please try it out if this applies to you.

If you were just using lerna bootstrap without any advanced hoisting concerns, feel free to choose from any of the package managers, they all offer robust workspaces implementations.

Temporarily polyfilling legacy package management commands​


If you really find yourself stuck and needing the legacy package management commands of lerna bootstrap, lerna add and lerna link in v7, you can install the @lerna/legacy-package-management package at the
same version as your lerna package, and this will polyfill the commands with their old implementations.

It's important to note that this is just a stop gap and this new package can be thought of as being in maintenance mode only - no new features will be considered for legacy package management concerns (such as lerna
bootstrap, lerna add and lerna link), and we will only look to merge critical patches and security updates.

If you find yourself in this position, please open an issue on the lerna repo so that we can learn more about the difficulties you are facing and help you find a way forward:

https://github.com/lerna/lerna/issues/new/choose

Background​
Lerna is the original monorepo/workspace tool in the JavaScript ecosystem. When it was created in 2015/2016 the ecosystem looked totally different, and there were no built in capabilities to handle working with multiple
packages in a single repository (a "workspace"). Commands like lerna bootstrap, lerna add and lerna link were all a critical part of the lerna project, because there were no other options.

However, the fact is that - for many years now - the package managers we know and love ( npm, yarn and pnpm) all fully support that concept of workspaces as a first-class use-case.

They have battle tested implementations covering adding, removing and linking local packages, and combining them with third party dependencies in a natural way.

This is the reason why, for the final several years of his tenure as lead maintainer of lerna, Daniel, had been encouraging folks to strongly reconsider their use of the legacy package management commands in lerna, and
instead leverage their package manager of choice to do what it does best.

We knew about this context from afar, but as new stewards of the project in 2022 we did not want to jump straight in and start removing capabilities without first taking the time to get familiar with the reality up close.
Now that we have been actively maintaining for a while, we are in full agreement with Daniel and others that the legacy package management commands in lerna needed to be retired.

By removing these legacy pieces which have better alternatives natively in package managers, we and the rest of the lerna community are now freed up to concentrate our efforts on things which are uniquely valuable
about lerna (such as, but not limited to, versioning and publishing), and making them the best they can be!

info

This same context is covered on the Lerna v7 discussion, if you have any specific concerns, please join us there and provide as much information as possible!

Frequently asked questions


This document is a work in progress.

How do I add a third party dependency to my Lerna repository?​


Lerna is not responsible for adding or linking your dependencies, that is what your package manager of choice (npm/yarn/pnpm) is best at. By using the workspaces feature of your package manager, all the linking of local
packages will happen automatically based on the relationships you set up in your package.json files.

You can check out the workspaces documentation for your package manager here:

npm (https://docs.npmjs.com/cli/using-npm/workspaces)
yarn (https://yarnpkg.com/features/workspaces)
pnpm (https://pnpm.io/workspaces)

NOTE: Because lerna itself predates the workspaces feature in package managers, there was historically a few commands (add, bootstrap and link) that attempted to fill that gap. Fortunately these commands are no
longer needed and lerna can focus on what it does best and let the package managers does the same.

New packages within the lerna repo​


You can use the lerna create command to create new packages within your lerna repo.
lerna create <packageName>

See the create docs for more options.

If you don't want to use lerna create , then you can still manually create a package by running npm init within a subdirectory of the packages folder and Lerna will automatically detect it.

Existing packages​
You can use lerna import <package> to transfer an existing package into your Lerna repository; this command will preserve the commit history.

lerna import <package> takes a local path rather than a URL. In this case you will need to have the repo you wish to link to on your file system.

How do I retry publishing if publish fails?​


In the case that some packages were successfully published and others were not, lerna publish may have left the repository in an inconsistent state with some changed files. To recover from this, reset any extraneous local
changes from the failed run to get back to a clean working tree. Then, retry the same lerna publish command. Lerna will attempt to publish all of the packages again, but will recognize those that have already been
published and skip over them with a warning.

If you used the lerna publish command without positional arguments to select a new version for the packages, then you can run lerna publish from-git to retry publishing that same already-tagged version instead of having
to bump the version again while retrying.

How does Lerna detect packages?​


By default, for npm and yarn, lerna uses the configured workspaces property in package.json to know what packages to operate on. For details on this property, see the npm documentation or the yarn documentation.

If you are using pnpm, you might have set npmClient to pnpm in lerna.json. In this case, Lerna will use the packages property in pnpm-workspace.yaml to know what packages to operate on. For details on this property,
see the pnpm documentation.

If you want lerna to focus on a particular subset of packages in your repo, you can leverage the packages property in lerna.json to search for packages.

Lerna 6: Obsolete Options


Nx and Lerna work together seamlessly in the same workspace.

When Lerna is running tasks with Nx and detects Nx target configuration, Lerna will respect this configuration during lerna run and delegate dependency detection to the Nx task runner.

Nx will run tasks in an order and with a concurrency that it determines appropriate based on the task graph that it creates. For more information, see Nx Mental Model: The Task Graph.

This behavior allows Nx to run tasks in the most efficient way possible, but it also means that some existing options for lerna run become obsolete.

Obsolete Options​
--sort and --no-sort​

When Nx targets are configured, Lerna will always run tasks in the order it deems is correct based on its knowledge of project and task dependencies, so --sort and --no-sort have no effect.

--parallel​

Lerna will use the task graph to determine which tasks can be run in parallel and do so automatically, so --parallel has no effect.

note

If you want to limit the concurrency of tasks, you can still use the concurrency global option to accomplish this.

--include-dependencies​

Lerna 6 will automatically run dependent tasks first when necessary, so --include-dependencies is obsolete. However, the flag can still be used to include tasks that are not required (e.g., running the tests of all the
dependent projects).

--ignore​

When used with Nx, --ignore will never cause lerna run to exclude any tasks that are deemed to be required task graph.

tip

The effects on the options above will only apply if:

1. nx.json exists in the root with the targetDefaults property defined.


2. The "nx" property is found in the package.json of a target package.

Otherwise, they will behave just as they would with Lerna's legacy task runner (if useNx is false).

Troubleshooting
This document contains solutions for certain issues our users encountered in the past while using Lerna.

Import Command​
Buffer problems during import​
When you try to import a repository which has many commits in it there is a chance that you get an error such as:
DeprecationWarning: Unhandled promise rejections are deprecated

or
Error: spawnSync /bin/sh ENOBUFS during ImportCommand.execute

Solution:​

Run lerna import with the --max-buffer flag and provide a large enough number (in bytes). At the writing of this entry the underlying default is 10MB, so you should keep this in mind.

Merge conflict commits cannot be imported ​


When you try to import a repository that contains merge commits that needed conflict resolutions, the import command fails with an error:
lerna ERR! execute Error: Command failed: git am -3
lerna ERR! execute error: Failed to merge in the changes.
lerna ERR! execute CONFLICT (content): Merge conflict in [file]

Solution​
Run lerna import with the --flatten flag to import the history in "flat" mode, i.e. with each merge commit as a single change the merge introduced.

Failing when git tree has uncommitted changes​


You will receive fatal: ambiguous argument 'HEAD': error, when the current project has uncommitted changes.

Solution​

Make sure to commit all the changes you have in your lerna project, before importing any packages using lerna import .

Publish Command​
Publish does not detect manually created tags in fixed mode with Github/Github Enterprise​
Github and Github Enterprise use lightweight Git tags when a release is created through the web ui, while Lerna uses annotated tags.

This can cause an issue where Lerna will ignore previously published releases which have been manually performed and tagged with the Github web ui.

For example if the publish history was as follows:

v1.1.0 was published and tagged with lerna publish


v1.2.0 was manually published and tagged with the Github web ui
v1.2.1 was manually published and tagged with the Github web ui

Running lerna publish now would detect v1.1.0 instead of v1.2.1 as the last released tag.

The implications of this depends on your usage of lerna publish :

The publish prompt would use v1.1.0 as the base for major/minor/patch suggestions.
When using the --conventional-commit flag:
would suggest a semver increment based on all the commits since v1.1.0 (including commits from v1.2.0, v1.2.1 etc)
The generated CHANGELOG.md files will repeat all the commits that have already been released in v1.2.0, v1.2.1 etc

Solution:​

If possible, use lerna publish over manual releases.

For new manual releases, use git tag -a -m <version> instead of using the Github web ui.

For existing lightweight tags, they can be converted to an annotated tag using something like this:
GIT_AUTHOR_NAME="$(git show $1 --format=%aN -s)"
GIT_AUTHOR_EMAIL="$(git show $1 --format=%aE -s)"
GIT_AUTHOR_DATE="$(git show $1 --format=%aD -s)"
GIT_COMMITTER_NAME="$(git show $1 --format=%cN -s)"
GIT_COMMITTER_EMAIL="$(git show $1 --format=%cE -s)"
GIT_COMMITTER_DATE="$(git show $1 --format=%cD -s)"
git tag -a -m $1 -f $1 $1
git push --tags --force

See this Stackoverflow post for more details

Publishing to a private npm registry (Artifactory, npm Enterprise, etc) ​


If lerna publish is failing ensure you have the following your package.json :
"publishConfig": {
"registry": "https://[registry-url]"
}

You may also need to add the following to your .npmrc file on the individual package(s):
registry = https://[registry-url]

info

Lerna always uses npm tooling to publish packages, regardless of the npmClient set in the lerna.json file. This means that any yarn or pnpm configuration will not be detected. To ensure successful publishing to a private
registry, make sure that npm is configured properly with environment variables or a .npmrc file.

Jest / Visual Studio Code Debugging​


It is possible to debug Jest tests in a Lerna-managed package using Visual Studio Code. Debugging with breakpoints works with the vscode launch configuration below in the monorepo's <root>/.vscode/launch.json
file. This example launches Jest for a single package my-package located in the monorepo.
{
"name": "Jest my-package",
"type": "node",
"request": "launch",
"address": "localhost",
"protocol": "inspector",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/lerna",
"runtimeArgs": [
"exec",
"--scope",
"my-package",
"--",
"node"
],
"args": [
"${workspaceRoot}/node_modules/jest/bin/jest.js",
"--runInBand",
"--no-cache",
"packages/my-package"
]
}

--runInBand avoids parallelizing tests across multiple processes


--no-cache helps avoid caching issues

Tested with Visual Studio Code v1.19.3 and Jest v22.1.4.

Getting Started
Lerna comes with a dedicated init command to assist you with both adding lerna to an existing repo, or creating one from scratch.

Starting from scratch​


In the simplest case, lerna init can be used to create a new repository in an empty directory. For that, we can run the following commands:
# Create an empty directory
mkdir ./new-lerna-workspace
# Change into the new directory
cd ./new-lerna-workspace
# Initialize lerna (using --dryRun to preview the changes)
npx lerna init --dryRun

Note that we have passed the --dryRun flag here, this allows us to see a preview of the changes that lerna init will make to our file system. This allows us to tweak the values of any other arguments we pass to lerna
init (such as --exact or --independent ) without having to worry about undoing any mistakes.

Once we are happy with the changes it will make, we can simply repeat the npx lerna init command but leave off the --dryRun flag.

You will now be up and running with a working git repository, including npm workspaces, with lerna available to create, version and publish any packages you wish to develop.

Adding lerna to an existing repo​


If you already have an existing repo, you can still add lerna to it using lerna init.

info

Lerna is not responsible for installing and linking your dependencies in your repo, your package manager is much better suited to that task.

Instead, we strongly recommend configuring your package manager of choice to use its workspaces feature:

npm (https://docs.npmjs.com/cli/using-npm/workspaces)
yarn (https://yarnpkg.com/features/workspaces)
pnpm (https://pnpm.io/workspaces)

When initializing lerna on an existing repo, it will need a way to know what packages it should operate on. If you are using your package manager's workspaces feature (see note above), then lerna will default to using the
workspaces patterns you have already configured. No extra arguments are required.

Alternatively, you can manually specify a set of patterns to match against instead by using the --packages flag for lerna init:
# Passing a single pattern
npx lerna init --packages="packages/*"
# Passing multiple patterns
npx lerna init --packages="foo/*" --packages="bar/*"

Editor Integrations
Nx Console displays the npm scripts for all your projects in the VS Code sidebar and allows you to run them with a single click or open the script definition in your editor.

Download​
VSCode​
If you are using VSCode, you can install the Nx Console VSCode Plugin from Marketplace. The Nx Console VSCode Plugin is built and maintained by the Nx team.

WebStorm​
If you are using WebStorm, you can install one of the available plugins:

nx-webstorm
Nx Console Idea

These plugins are NOT built or maintained by the Nx team. They are maintained by independent community contributors.

Nx Console for VSCode​

Install from the VSCode Marketplace


Contribute on GitHub

Cache Task Results


When it comes to running tasks, caching etc., Lerna and Nx can be used interchangeably. When we say "Lerna can cache builds", we mean that Lerna uses Nx which can cache builds.

It's costly to rebuild and retest the same code over and over again. Lerna uses a computation cache to never rebuild the same code twice.

Setup​
Lerna via Nx has the most sophisticated and battle-tested computation caching system. It knows when the task you are about to run has been executed before, so it can use the cache to restore the results of running that
task.
tip

If you don't have nx.json , run npx lerna add-caching.

To enable caching for build and test, edit the cacheableOperations property in nx.json to include the build and test tasks:

nx.json
{
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": ["build", "test"]
}
}
}
}

info

Note, cacheableOperations need to be side effect free, meaning that given the same input they should always result in the same output. As an example, e2e test runs that hit the backend API cannot be cached as the
backend might influence the result of the test run.

Now, run the following command twice. The second time the operation will be instant:
lerna run build --scope=header

Terminal Output
> lerna run build --scope=header
> header:build [existing outputs match the cache, left as is]
> [email protected] build
> rimraf dist && rollup --config
src/index.tsx → dist...
created dist in 858ms
————————————————————————————————————————————————————————————————
> Lerna (powered by Nx) Successfully ran target test for project header (4ms)
Nx read the output from the cache instead of running the command for 1 out of 1 tasks.

Replaying from Cache​


When Lerna determines that the inputs for a task have not changed, it recreates the outputs of that task as if it actually ran on your machine - but much faster. The outputs of a cached task include both the terminal output
and the files created in the defined output directories for that task.

You can test this out by deleting the dist folder that the header:build task outputs to and then running lerna run build --scope=header again. The cached task will replay instantly and the correct files will be present
in the dist folder.
header/
└── dist/ <-- this folder gets recreated

If your task creates output artifacts in a different location, you can change the output folder(s) that are cached. You can also customize which inputs will invalidate the cache if they are changed.

Advanced Caching​
For a more in-depth understanding of the caching implementation and to fine-tune the caching for your repo, read How Caching Works.

Local Computation Caching​


By default, Lerna (via Nx) uses a local computation cache. Nx stores the cached values only for a week, after which they are deleted. To clear the cache run nx reset , and Nx will create a new one the next time it tries to
access it.

You might also like