Lerna vs Nx: a monorepo publisher that now builds inside an Nx workspace
Lerna is a fast, modern build system for managing and publishing multiple JavaScript/TypeScript packages from the same repository.
At a glance
- What is it?
- Lerna still versions and publishes JavaScript and TypeScript packages for monorepos, but stewardship moved to Nx and the repository is now an Nx workspace. The README is a wall of outbound links, so nothing about the command surface can be learned from the project itself.
- Who is it for?
- Take Lerna when the release graph is your problem: several publishable packages that need version bumps and coordinated pushes. Skip it when you only want one repository with several linked packages, since the npm workspaces array in this project's own root manifest already covers that, and this project relies on it.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The README is a list of links, not a manual
The first line of the README is a notice rather than an explanation: it points at issue 3121 for a change of stewardship to Nx, then at a blog post arguing the tool is alive. Everything after that is an exit sign. The links go to lerna.js.org, to a Getting Started page and a Features page, and to an Nx blog. Bug reports and pull requests are routed to CONTRIBUTING.md, and questions go to a Discord #forum channel. The core team is named: Victor Savkin, James Henry, Benjamin Cabanes, Juri Strumpflohner, followed by a table of contributors. No command, no config key and no file layout appears anywhere in the file. Someone weighing Lerna against the alternatives learns from this page that a team exists and that the documentation lives somewhere else, then has to go find it. That is the entire onboarding surface the project offers on its own landing page.
nx.json sits next to lerna.json, and the dev dependencies are all Nx
The handover shows up in the tree, not just in the notice. An nx.json sits at the repository root next to lerna.json, and the dev dependencies are Nx packages pinned to a single version across the board:
"@nx/devkit": "23.2.1",
"@nx/esbuild": "23.2.1",
"@nx/eslint": "23.2.1",
"@nx/eslint-plugin": "23.2.1",
"@nx/js": "23.2.1",
"@nx/plugin": "23.2.1"That shapes what a version bump costs you. The v9.0.7 release is dated 2026-03-13, v10.0.0 landed on 2026-07-29 and v10.0.1 on 2026-08-19, so a major version arrived in the middle of the year, and the last push was on 2026-09-29. Whether a given Lerna major pulls Nx in as a runtime dependency is not answered by the root manifest, because that file is private and scoped to the workspace. The manifest to read for the shipped package is the one under packages/lerna, and the README points to neither.
Three npm workspaces, and a Yarn pin the package manager does not use
The root manifest is called lerna-monorepo, carries `"private": true`, and describes itself in three words: lerna dog-fooding lerna. The workspaces array names three places, and a Volta block pins the toolchain to one Node release and one npm release:
"workspaces": [
"packages/lerna",
"website",
"libs/e2e-utils"
],
"volta": {
"node": "26.9.0",
"npm": "12.0.2",
"yarn": "1.22.22"
},
"packageManager": "[email protected]"The yarn pin is the oddity. packageManager declares [email protected], the Volta block pins that same npm, and then Volta also names Yarn 1.22.22. A contributor who reads the Volta block and reaches for Yarn is not running the package manager the manifest asks for, and nothing in the repository says which one wins. Two configuration files at the root, lerna.json and nx.json, mean settings are spread across three sources for a workspace holding one CLI package, a website and a directory named libs/e2e-utils. The root licence field is MIT, which covers this workspace rather than the published package.
The root manifest runs commands three different ways
Every entry in the scripts block of package.json is written in a different style from its neighbour, which is worth knowing before you add one. Two scripts wrap shell files, tools/scripts/build.sh and tools/scripts/local-registry.sh. Two invoke files directly through node, including tools/scripts/e2e-build-package-publish.ts. The rest delegate to Nx targets:
"build": "tools/scripts/build.sh",
"e2e-build-package-publish": "node tools/scripts/e2e-build-package-publish.ts",
"e2e-start-local-registry": "node tools/scripts/e2e-start-local-registry.js",
"format:check": "prettier --check '**/*.{js,mjs,ts,tsx,css,yml,json}'",
"format:write": "prettier --write '**/*.{js,mjs,ts,tsx,css,yml,json}'",
"integration": "nx integration integration --maxWorkers=2",
"lerna-release": "nx build lerna --no-dte --no-cloud && node tools/scripts/lerna-release.mjs",
"lint": "nx run-many -t lint",
"local-registry": "tools/scripts/local-registry.sh",
"test": "nx run-many -t test"The integration line sets its own concurrency with --maxWorkers=2, and the release line hands Nx the flags --no-dte and --no-cloud before running a script named for the release, so the flags on that line are worth reading in the Nx docs rather than guessing at. The consequence for a newcomer is that shell entry points, direct node calls and Nx target syntax all have to be learned before any code changes, and no file in the repository records which style a new script is meant to use.
lerna.json exists, and not one key inside it is documented
Some of what you need is simply absent. There is no install command, no first command to run, no list of the keys allowed inside lerna.json, no version policy, and no rollback path. The config file itself sits at the root of the repository, and the README does not document a single key inside it, so a working configuration cannot be reconstructed by reading the source. The same gap covers upgrades. A CHANGELOG.md sits at the root too, and the README does not summarise what v10.0.0 changed over the v9.0.7 line, which is the exact information an upgrade decision needs. Anyone moving between those versions has to open the changelog themselves and then reconcile it with the guides at lerna.js.org, which track the current release rather than the one pinned in a lockfile. Check the behaviour you depend on against the tag you would actually install.
Releases get rehearsed against .verdaccio, and consumers get no registry template
Publishing is exercised without touching the public registry. A .verdaccio directory sits at the root, and three of the ten scripts exist to run a registry locally: e2e-start-local-registry, e2e-build-package-publish, and local-registry, which wraps tools/scripts/local-registry.sh. The e2e, integration and __fixtures__ directories support the same loop. That buys the project a repeatable check that a build can be produced and pushed somewhere. It does not leave you a template. Nothing in the repository shows how a consuming project should point Lerna at a private or self hosted registry, and a .env.local file sits at the root with no statement of what belongs in it. Teams publishing to an internal registry therefore have no worked example to copy and no documented dry run to catch a wrong setting before a real release.
AGENTS.md and CLAUDE.md are repository files, not a shipped feature
Several root entries answer a question the README never raises. AGENTS.md and CLAUDE.md sit next to CODE_OF_CONDUCT.md, CONTRIBUTING.md, socket.yml and .all-contributorsrc, and the README links to none of them; CONTRIBUTING.md is the only governance file it names. The project's own one-line description covers managing and publishing packages and says nothing about models, prompts or code generation. So if you arrive looking for an AI capability, what you find first is working instructions for the repository itself, and those files are not part of what npm delivers to a consuming project. The same reasoning applies to .prettierrc.yml, eslint.config.mjs and .env.local. They govern how this workspace is built and checked, and none of them is a configuration surface your repository inherits by adding Lerna.
Where Lerna, Nx and Turborepo split the work
Lerna's scope is narrow on purpose: versioning and publishing several JavaScript or TypeScript packages out of one repository. Nx, which took over stewardship, is a build system first, and this repository now runs its lint, test and integration work through Nx targets rather than npm scripts alone. The two overlap on building and diverge on releasing. Turborepo, the other name that comes up for this job, runs tasks and caches their outputs, and the version-and-publish step is not its work. So adopt Lerna when the release graph is the problem rather than the task cache. Skip it when you only need one repository with several packages linked, because the workspaces array in this project's own manifest already does that part. And read the v10.0.0 changelog entry before leaving 9.0.7, since the docs site follows the current release, not the one in your lockfile.
Editorial conclusion
Take Lerna when the release graph is your problem: several publishable packages that need version bumps and coordinated pushes. Skip it when you only want one repository with several linked packages, since the npm workspaces array in this project's own root manifest already covers that, and this project relies on it. Whatever you decide, read the v10.0.0 entry in the root CHANGELOG.md before leaving the 9.0.7 line, because no other file in the repository will summarize it for you.
Frequently asked questions
How do I install Lerna?
The README carries no install command at all. It points to lerna.js.org and to a Getting Started page at lerna.js.org/docs/getting-started, and it links the package on npm, so both the install steps and the package location sit one hop from the landing page.
How do I install Lerna on macOS?
Nothing in the repository is specific to macOS or to any other platform. The closest thing to a platform requirement is the Volta block in the root manifest, which pins Node 26.9.0 and npm 12.0.2, and those pins are for building Lerna rather than for consuming the published package.
How do I use Lerna?
The README names no commands, so usage has to come from the Features page at lerna.js.org/docs/features and the guides linked from the same site. What the repository does show is the shape of a setup: three npm workspaces named packages/lerna, website and libs/e2e-utils, and a release script that builds the lerna package through Nx before running tools/scripts/lerna-release.mjs.
What is Lerna used for?
Managing and publishing several JavaScript or TypeScript packages out of one repository, which is the scope the project sets for itself. Configuration lives in lerna.json at the repository root, next to package.json, nx.json and tsconfig.base.json, rather than inside package.json.
What is lerna.json?
It is the configuration file at the repository root, and the README does not document a single key inside it. A team starting from this repository cannot derive a working config from the source alone, so the documentation site is the only starting point named.
What is Lerna AI?
Nothing in the README describes an AI feature, and the project's own description covers package management and publishing only. The root of the repository does carry AGENTS.md and CLAUDE.md, but the README links to neither, so what you find first is working instructions for the repository rather than a shipped capability.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/lerna-lerna)