lerna.js.org
No paid content found
Categories: Development
Lerna is a fast, modern build system for managing and publishing multiple JavaScript/TypeScript packages from the same repository.
Related questions
More questions →Nx vs Lerna: Which Monorepo Tool Should You Use for JavaScript/TypeScript?
Nx and Lerna are not direct competitors anymore. Lerna is a fast, modern build system for managing and publishing multiple JavaScript/TypeScript packages from the same repository, and it now uses Nx under the hood for task running and caching. In practice: choose Nx when you want a full monorepo platform (graph, caching, generators, plugins); choose Lerna when your main job is versioning and publishing many packages and you want a lighter, publish-focused workflow. Many teams run both, since Lerna delegates the heavy task-running work to Nx.
What Nx is and what it solves
Nx is a build system and monorepo toolkit. It targets the problems that appear once a repository holds several apps and libraries:
- Task orchestration — it figures out the dependency order between projects and runs only what is affected by a change.
- Computation caching — task results are cached locally and (optionally) remotely, so unchanged work is replayed instead of recomputed.
- Project graph — a model of how projects depend on each other, used to decide what to build, test, and lint.
- Generators and plugins — scaffolding for apps, libraries, and framework-specific setups.
The value shows up as the repo grows. On a two-package repo the overhead is hard to justify; on a repo with dozens of projects and a slow CI pipeline, affected-only runs and caching are the main reason teams adopt it.
How Lerna's role changed
Lerna historically did two things: run tasks across packages and manage versions/publishing. The task-running half is now handled by Nx, which Lerna uses for its build system. That leaves Lerna focused on the part it is still known for:
- Versioning — deciding and bumping versions across packages.
- Publishing — pushing packages to a registry in the right order.
- Changelog and release flow — managing the release metadata around a multi-package repo.
So the comparison is less "Nx or Lerna" and more "which layer do you need." If your pain is slow builds and CI, that is Nx's layer. If your pain is coordinating releases of many packages, that is Lerna's layer.
Key differences at a glance
| Dimension | Nx | Lerna |
|---|---|---|
| Primary focus | Build system, task orchestration, caching | Versioning and publishing packages |
| Task running | Core strength; affected-only, dependency-aware | Delegates to Nx |
| Caching | Local and remote computation caching | Provided through its Nx integration |
| Project graph | Yes, central to how it decides what to run | Not its focus |
| Generators/plugins | Extensive, framework-oriented | Not its focus |
| Best fit | Large repos, heavy CI, mixed app/library code | Repos whose main challenge is releasing many packages |
Which one fits your project
Use Nx when:
- CI is slow and you want affected-only builds plus caching.
- The repo mixes applications and libraries that depend on each other.
- You want generators and plugins to standardize how projects are created.
Use Lerna when:
- You publish many packages and release coordination is the main pain.
- You want a publish-focused tool without adopting a full platform.
- You are already on Lerna and the task-running side is handled.
Use both when you publish multiple packages and need fast, cached, dependency-aware task execution — this is the configuration Lerna itself points toward, since its build system is Nx.
Combining or migrating in an existing repo
The practical path is incremental rather than a rewrite:
- Confirm your current setup — identify how tasks are currently run and how versions are published.
- Adopt Nx for task running — let it own build/test/lint orchestration so affected-only runs and caching apply.
- Keep Lerna for releases — leave versioning and publishing where they are if that flow works.
- Verify — after switching task running, check that the same projects build and test, and that CI time drops on changes that touch few projects.
Common snags: expecting caching to help before task inputs are configured correctly, and assuming a migration requires moving every package at once. It does not — the two tools are designed to sit in the same repository.
What Is Lerna and How Does It Manage JavaScript Monorepos?
Lerna is a build system for managing and publishing multiple JavaScript or TypeScript packages from a single repository. It fits teams that keep several interdependent packages together and need coordinated versioning, publishing, and task running. If you only have one package, or your packages never share code or releases, Lerna adds overhead without much benefit.
The core problem Lerna solves
A monorepo puts many packages in one repository. That makes sharing code easy, but it creates coordination work:
- Which packages changed since the last release?
- What version should each changed package get?
- In what order should packages be published so dependencies exist first?
- How do you run a build or test across all packages without doing it manually?
Lerna addresses these by understanding the dependency graph between your packages and acting on it.
How Lerna manages a monorepo
Versioning
Lerna tracks which packages changed and updates their versions together or independently. It supports two common modes:
- Fixed mode: all packages share one version number and are released together.
- Independent mode: each package gets its own version, so you can release only what changed.
The choice matters. Fixed mode is simpler and suits tightly coupled packages. Independent mode gives finer control but requires more discipline.
Publishing
When you publish, Lerna determines the correct order based on inter-package dependencies, so a package that depends on another is published after its dependency. It can also create git tags and update changelogs as part of the release.
Running tasks across packages
Lerna can run a command (build, test, lint) across multiple packages, and it can scope that to only the packages affected by recent changes. This is the part that saves the most time in large repos, because you avoid rebuilding everything on every change.
Lerna and Nx
Lerna is now part of the Nx ecosystem. The relationship matters when you choose tooling:
- Lerna handles the monorepo versioning and publishing workflow.
- Nx provides the broader task running, caching, and project graph capabilities.
In practice, Lerna can use Nx under the hood for task execution and caching. If you already use Nx, Lerna fits as the release layer. If you only need publishing and versioning, Lerna can stand alone.
Lerna vs. plain npm/yarn workspaces
| Concern | npm/yarn workspaces | Lerna |
|---|---|---|
| Linking local packages | Yes | Yes (builds on workspaces) |
| Coordinated versioning | No | Yes |
| Ordered publishing | No | Yes |
| Changelog generation | No | Yes |
| Running tasks across packages | Limited | Yes, with affected-package scoping |
Workspaces solve dependency linking. Lerna solves the release and task-orchestration layer on top. Many projects use both: workspaces for installation, Lerna for versioning and publishing.
When Lerna is the right choice
Consider Lerna when:
- You maintain multiple packages that depend on each other.
- You need repeatable, ordered releases rather than manual
npm publishper package. - You want to run builds or tests only for packages affected by a change.
- You are already in or moving toward the Nx ecosystem.
Look elsewhere when:
- You have a single package.
- Your packages are released independently by different teams with no shared release process.
- You only need local linking and never publish.
Where to start
Begin with the Lerna documentation at lerna.js.org. The typical first steps are initializing Lerna in an existing repository, defining your package locations, and choosing fixed or independent versioning before your first release. Getting the versioning mode right early avoids a painful migration later.
What Is TypeScript and How Do You Use It?
TypeScript is a typed superset of JavaScript: every valid JavaScript program is also valid TypeScript, but TypeScript adds optional static types that a compiler checks before your code ever runs. You use it by installing the typescript package, writing .ts files, and compiling them to plain .js with the tsc command. It fits best when a codebase grows past a few files or several people, where catching type errors at build time is cheaper than debugging them at runtime. For a throwaway script, plain JavaScript is usually faster to write.
What TypeScript actually adds
TypeScript does not change how JavaScript runs. Browsers and Node.js still execute JavaScript, so the types are erased during compilation. What you gain is a checking pass:
- Static type checking — the compiler reads your annotations and flags mismatches before execution.
- Earlier error detection — mistakes like calling a method that does not exist surface in your editor or in
tsc, not in production. - Better tooling — editors use the type information for autocomplete, inline documentation, and safe rename/refactor operations.
- Self-documenting interfaces — function signatures and object shapes describe intent without extra comments.
The trade-off is a build step and some annotation overhead. Types are optional, so you can adopt them gradually.
The basic workflow
1. Install the compiler
npm install --save-dev typescript
This adds tsc to your project. You can also install it globally, but a local dev dependency keeps the version consistent across machines and CI.
2. Write a .ts file
function greet(name: string): string {
return `Hello, ${name}`;
}
console.log(greet("Ada"));
The : string annotations tell the compiler what name and the return value must be. If you call greet(42), tsc reports an error instead of letting it fail silently at runtime.
3. Compile
npx tsc greet.ts
Expected result: a greet.js file next to the source, containing the same logic with the type annotations removed. That .js file is what Node.js or the browser runs.
4. Add a config file
For anything beyond one file, create a tsconfig.json so you do not repeat flags:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"outDir": "dist"
},
"include": ["src"]
}
Then just run npx tsc. strict: true turns on the stricter checks, including strictNullChecks, which is where most real-world type safety comes from. Turning it on later in a large project is painful, so enable it early.
Key features with examples
Type annotations
let count: number = 0;
let names: string[] = ["Ada", "Grace"];
Annotations can be omitted when TypeScript can infer the type, which it does for most assignments.
Interfaces
interface User {
id: number;
email: string;
nickname?: string; // optional
}
function sendWelcome(user: User) {
console.log(`Welcome, ${user.nickname ?? user.email}`);
}
An interface describes the shape an object must have. Passing an object missing id or email is a compile error.
Generics
function first<T>(items: T[]): T | undefined {
return items[0];
}
const n = first([1, 2, 3]); // n: number | undefined
const s = first(["a", "b"]); // s: string | undefined
Generics let one function work across types while keeping the relationship between input and output. T is a placeholder filled in at the call site.
Using TypeScript in an existing JavaScript project
You do not have to convert everything at once:
- Add
typescriptand atsconfig.jsonwith"allowJs": trueso.jsfiles are included. - Rename files to
.tsone at a time, starting with the most central modules. - Add types to function boundaries first — parameters and return values — and let inference handle the internals.
- Turn on
strictonce the obvious errors are cleared.
Most build tools and bundlers accept TypeScript through a loader or plugin, so you rarely need to run tsc by hand in a modern setup. In monorepos, tools like Lerna manage multiple JavaScript/TypeScript packages from one repository, and each package can carry its own tsconfig.json while sharing a base config. That is a common reason teams introduce TypeScript: a shared type contract between packages catches breaking changes at build time rather than at integration.
Common sticking points
anyeverywhere — annotating everything asanydisables the checks you installed TypeScript for. Preferunknownand narrow it.- Ignoring
strictNullChecks— most runtime crashes come fromnull/undefined, which this flag catches. - Types at runtime — TypeScript types do not exist after compilation, so you still need runtime validation for data from APIs, files, or user input.
- Build configuration drift — mismatched
target/modulesettings betweentsconfig.jsonand your bundler cause confusing errors; keep them aligned.
If your goal is safer JavaScript in a growing codebase, start with a tsconfig.json, enable strict, and convert files incrementally. If you are writing a small script that will not be maintained, plain JavaScript remains the simpler choice.
What Is a Monorepo and When Should You Use One for JavaScript Projects?
A monorepo is a single version-controlled repository that holds the source code for multiple projects, packages, or services. Instead of giving each package its own repository (a "polyrepo" setup), you keep them together and manage their relationships in one place. For JavaScript and TypeScript teams, the appeal is usually straightforward: shared code becomes easier to reuse, changes that span several packages can land in one commit, and dependency versions stop drifting apart. The cost is equally real — you take on more build and CI complexity, and you need tooling that understands which packages changed and what depends on what.
This article explains the model, compares it with polyrepos, and gives you concrete criteria for deciding whether it fits your project.
Monorepo vs. polyrepo: the core difference
The distinction is not about how many packages you have. It is about where the boundaries sit between "one repository" and "many repositories," and what those boundaries force you to do.
| Dimension | Monorepo | Polyrepo |
|---|---|---|
| Code location | All packages in one repo | One repo per package/service |
| Cross-package change | One commit, one review, one CI run | Multiple commits across repos, coordinated releases |
| Shared code | Direct import via workspace links | Published package, version bump, or git submodule |
| Versioning | Often unified or independently managed in one place | Naturally independent, but easy to drift |
| Access control | Repo-level; finer control needs extra tooling | Per-repo permissions out of the box |
| CI scope | Needs change detection to avoid rebuilding everything | Each repo's CI is naturally scoped |
| Onboarding | One clone, one install | Clone only what you need |
| Repo size | Grows with every package | Stays small per repo |
Neither column is universally better. A monorepo trades isolation for coordination; a polyrepo trades coordination for isolation.
What a monorepo actually gives you
Shared code without publishing overhead
In a polyrepo, reusing an internal utility means publishing it, bumping its version, and updating consumers. In a monorepo with a workspace setup (npm, Yarn, or pnpm workspaces), packages can reference each other directly. You edit the shared package and its consumers in the same working tree.
Atomic, cross-package changes
If a change to a shared type breaks three consumers, a monorepo lets you fix all four in one pull request. Reviewers see the full blast radius. In a polyrepo, that same change becomes a sequence of releases where the intermediate states can be broken.
Consistent tooling and dependencies
One lint config, one TypeScript config base, one test runner setup. You can still allow per-package overrides, but the default is consistency, which reduces "it works in my package" problems.
Easier refactoring and discovery
Renaming a function or moving a module across package boundaries is a single search-and-replace plus a build. You can also see every consumer of an internal API, which makes deprecation decisions less risky.
The trade-offs you should expect
Build and task orchestration becomes a real problem
Once you have dozens of packages, running every test and build on every change is wasteful. You need tooling that can:
- Detect which packages changed since a given commit or branch.
- Build a dependency graph and run tasks in the correct order.
- Cache results so unchanged packages are skipped.
This is the layer that tools like Lerna, Nx, Turborepo, and similar systems address. The specific choice matters less than the capability: change detection, task graph, and caching.
CI cost and time
Without caching and affected-only runs, CI in a monorepo can be slower and more expensive than in a polyrepo, because a naive pipeline rebuilds everything. With them, it is often comparable or better, since you avoid re-running unchanged work.
Access control and ownership
A monorepo makes it harder to say "only the payments team can merge to the payments service." You can approximate this with CODEOWNERS files and branch protection rules, but it is not the same as separate repositories. If strict isolation is a hard requirement, weigh this carefully.
Repository size and clone time
Large monorepos get big. Shallow clones, sparse checkouts, and partial clone features help, but they add setup steps for contributors.
Release management
You must decide between unified versioning (all packages share a version) and independent versioning (each package versions on its own). Unified is simpler to reason about; independent is more flexible but requires discipline and tooling to keep changelogs and dependency ranges correct.
When a monorepo fits well
Consider a monorepo when most of these are true:
- You have multiple packages that genuinely depend on each other and change together.
- You want to enforce shared standards (linting, TypeScript config, testing) across teams.
- Your team is willing to invest in build tooling and CI caching.
- You value atomic changes across package boundaries more than strict per-repo isolation.
- You are building a product with a shared design system, shared types, or a shared SDK alongside apps.
A common example: a web app, a mobile app, and a shared component library that all evolve together. A change to a shared button component should be verifiable against both apps in one place.
When a monorepo does not fit
A polyrepo is often the better choice when:
- Packages are truly independent and rarely change together.
- Different teams need hard access boundaries for compliance or security reasons.
- Packages have very different release cadences and you do not want to coordinate them.
- The repository would become so large that clone and CI times hurt daily work, and you are not prepared to invest in tooling.
- You are experimenting with unrelated projects that share nothing but a language.
A useful rule of thumb: if you would never make a single commit that touches two of the packages, the coordination benefit of a monorepo is small.
A practical way to decide
- List your packages and draw the dependency edges between them. Count how many edges cross what would be repository boundaries.
- Estimate how often a change touches more than one package. If it is frequent, a monorepo helps; if it is rare, it mostly adds overhead.
- Check your CI budget and willingness to adopt caching and affected-only task running.
- Confirm your access-control requirements. If per-package permissions are mandatory, plan for CODEOWNERS and branch rules, or reconsider.
- Start small if you proceed: put two or three related packages in one repo first, set up workspace linking, and add change detection before the package count grows.
Where tooling fits in
A monorepo is a repository layout, not a tool. What makes it practical at scale is the build system around it: workspace linking for local dependencies, a task runner that understands the dependency graph, caching to skip unchanged work, and a publishing flow that handles versioning and changelogs. Lerna, for example, is a build system for managing and publishing multiple JavaScript/TypeScript packages from the same repository, and it is often used alongside or in combination with task runners like Nx. The right question is not "which tool is best" but "does my setup detect changes, order tasks correctly, and cache results?" If yes, the monorepo stays manageable as it grows.
Summary
A monorepo puts multiple packages in one repository to make shared code, atomic changes, and consistent tooling easier. It pays off when packages genuinely depend on each other and your team invests in change detection, task orchestration, and CI caching. It costs you isolation, access-control granularity, and setup complexity. Decide by measuring how often changes cross package boundaries and how much coordination pain you currently feel — not by whether monorepos are fashionable.
Website Overview
Identifiable technologies and additional version or configuration signals make the service easier to fingerprint, which may help targeted scanners narrow their checks. An established domain and managed infrastructure suggest continuity of operations and may support dependable delivery, although neither guarantees service quality.
Domain and Registration
Registered in 1996, this domain has about 30 years of history. That suggests continuity, although ownership and purpose may have changed. Transfer-protection status is present, helping reduce the risk of unauthorized domain transfers. The registrar is NameCheap, Inc., a widely used domain service provider. The domain uses the common .org extension, which is not an independent safety signal.
DNS and Email
Nameservers are provided by Cloudflare, indicating managed DNS hosting. MX records point to the improvmx.com email service. DNSSEC is enabled, allowing validating resolvers to authenticate signed DNS data. No CNAME was found; the observed records resolve directly to addresses. SPF and DMARC are configured. DKIM status is unknown.
TLS and Certificates
The public key uses EC with 256 bits. The server supplied a complete certificate chain. No organization name is present in the certificate; the available fields are consistent with domain validation. The certificate was issued by Let's Encrypt, commonly associated with automated certificate services. The certificate's total validity is about 89 days, consistent with a short renewal cycle.
HTTP and Browser Security
The checked browser-security headers were not detected, leaving fewer explicit browser-side safeguards. CORS permits any origin to read this response. This is common for public resources; sensitive responses need narrower handling. No X-Powered-By header was found, reducing one common source of backend fingerprinting information. The cf-ray, x-cache, x-served-by, via response header indicates a CDN or caching proxy in the delivery path. No obvious internal addresses or debug information were found in the headers.
Technology Stack Analysis
The public page identifies Docusaurus 3.10.2, Cloudflare, Fastly, with exact versions exposed for 1 technologies. These details can narrow vulnerability checks, although exposure alone is not a vulnerability.
Search and Social Sharing
The Generator tag identifies Docusaurus v3.10.2, making the publishing system easier to fingerprint. Open Graph is partially configured; og:type is missing. Twitter Card metadata is configured. The page declares 2 language or regional alternatives using hreflang. The title has 21 characters, within a common display range.
Hosting and Email
Pages, Search and Sharing
| Meta description | Lerna is a fast, modern build system for managing and publishing multiple JavaScript/TypeScript packages from the same repository. |
|---|---|
| Canonical URL | https://lerna.js.org/ |
| Language | English (default) |
| Twitter Card | summary_large_image |
Social Sharing Preview
6 fieldsrobots.txt (opens in a new tab)
HTTP 404No robots.txt found
Sitemaps
1
Registration details RDAP / WHOIS
| Registrar | NameCheap, Inc. |
|---|---|
| Registered | 1996-06-26 |
| Expires | 2032-06-25 |
| Domain status | client transfer prohibited |
| Nameservers | miles.ns.cloudflare.com、pam.ns.cloudflare.com |
| DNSSEC | signed |
DNS records
| Type | Name | Value | TTL | Priority |
|---|---|---|---|---|
| A | lerna.js.org | 104.26.8.84 | 300 | — |
| A | lerna.js.org | 104.26.9.84 | 300 | — |
| A | lerna.js.org | 172.67.73.64 | 300 | — |
| AAAA | lerna.js.org | 2606:4700:20::681a:854 | 300 | — |
| AAAA | lerna.js.org | 2606:4700:20::681a:954 | 300 | — |
| AAAA | lerna.js.org | 2606:4700:20::ac43:4940 | 300 | — |
| MX | js.org | mx1.improvmx.com | 300 | 10 |
| MX | js.org | mx2.improvmx.com | 300 | 20 |
| NS | js.org | miles.ns.cloudflare.com | 86400 | — |
| NS | js.org | pam.ns.cloudflare.com | 86400 | — |
| TXT | js.org | github-verification=Co5XEGjgZ54phI90tdeEbcXBt0LErl0nKNUpqPmR | 300 | — |
| TXT | js.org | v=spf1 -all | 300 | — |
| DS | js.org | 2371 13 2 bb5749b06b705cabaa999f6adc60b60e528c502078e1a1075206a852956d8670 | 3600 | — |
| DMARC | _dmarc.js.org | v=DMARC1; p=reject; pct=100; rua=mailto:[email protected]; sp=reject; aspf=s; | 300 | — |
TLS and certificates
| Assessment | Normal configuration |
|---|---|
| Supported protocols | TLSv1.2、TLSv1.3 |
| Negotiated protocol | TLSv1.3 |
| Certificate subject | js.org |
| Issuer | Let's Encrypt |
| Valid until | 2026-11-27T14:02 · Remaining when checked: 66 days |
| Verification details | Certificate trust: Passed · Hostname match: Passed |
HTTP response headers
| Header | Value |
|---|---|
| content-type | text/html; charset=utf-8 |
| cache-control | max-age=600 |
| server | cloudflare |
| access-control-allow-origin | * |
Identified technologies
Recent Updates
- Website images
- Screenshots
- Network details
- Website Technologies
- Pages and Search Information
- HTTP Response Information
- TLS and certificates
- DNS Information
- Domain Registration
- Website profile
- Website Description
- Website Name
- Website profile
- Website Description
- Website Name
User reviews (0)