Skip to main content

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:
- footer@1.0.1
- header@1.0.1
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.