DEV Community

楊東霖
楊東霖

Posted on • Originally published at devtoolkit.cc

Nx vs Turborepo vs Lerna: Choosing Your Monorepo Tool in 2026

Monorepos — single Git repositories containing multiple projects or packages — have become the default architecture at companies like Google, Meta, and Microsoft. In the JavaScript ecosystem, the rise of monorepos has spawned a competitive tooling landscape: Nx, Turborepo, and Lerna are the three most prominent options, each taking a different philosophy to solving the same core problem: making large codebases fast and maintainable.

This guide compares all three in depth — their architecture, caching strategies, task orchestration, ecosystem integrations, and the scenarios where each shines.

Why Monorepos? The Problem They Solve

Before comparing tools, it's worth understanding what problem they solve. A monorepo containing 20 packages has 20 sets of dependencies, 20 build pipelines, and 20 test suites. Without tooling, npm install in the root, then building every package in sequence, would take 30+ minutes on any non-trivial codebase.

Monorepo tools solve this with three mechanisms:

  • Dependency graph analysis: Understand which packages depend on which, so changes are only propagated where needed
  • Intelligent task scheduling: Run independent tasks in parallel, dependent tasks in sequence
  • Caching: Skip tasks whose inputs haven't changed — build once, reuse everywhere

Lerna: The Pioneer

Lerna was the first major JavaScript monorepo tool, released in 2015. It pioneered the concept of managing multiple npm packages in a single repository and automating versioning and publishing. For years, "monorepo" and "Lerna" were nearly synonymous in the JS community.

How Lerna Works

Lerna works on top of a package manager's workspace protocol (npm workspaces, yarn workspaces, or pnpm workspaces). It provides two key capabilities:

  • Task running: Run scripts across all packages, with change detection to skip unchanged ones
  • Publishing: Version bumping (fixed or independent versioning) and npm publish automation across all packages
# lerna.json
{
  "version": "independent",
  "npmClient": "pnpm",
  "useWorkspaces": true,
  "packages": ["packages/*", "apps/*"],
  "command": {
    "publish": {
      "conventionalCommits": true,
      "message": "chore(release): publish"
    }
  }
}

# Run build across all changed packages
npx lerna run build --since origin/main

# Publish all changed packages
npx lerna publish --conventional-commits
Enter fullscreen mode Exit fullscreen mode

Lerna + Nx Power Mode

In 2022, Nrwl (the company behind Nx) took over Lerna's maintenance and integrated Nx's task runner as Lerna's default engine. Modern Lerna (v6+) uses Nx under the hood for caching and task orchestration, meaning you get Lerna's publishing automation with Nx's performance.

# lerna.json — enable Nx integration
{
  "version": "independent",
  "useWorkspaces": true,
  "$schema": "node_modules/lerna/schemas/lerna-schema.json",
  "useNx": true,  // Enable Nx task runner
  "npmClient": "npm"
}
Enter fullscreen mode Exit fullscreen mode

When to Use Lerna

Lerna's sweet spot is open-source libraries that publish multiple packages to npm. If your primary concern is versioning coordination and publishing automation across packages (e.g., a component library shipping 20 independent packages), Lerna's conventional commits integration and changelog generation are best-in-class. For pure task running and caching, Turborepo or Nx are stronger.

Turborepo: Speed-First Simplicity

Turborepo was built by Jared Palmer and acquired by Vercel in 2021. Its philosophy is radical simplicity: a minimal configuration file, zero opinions about your project structure, and an obsessive focus on making builds fast through caching.

How Turborepo Works

Turborepo reads your turbo.json to understand task dependencies and caching rules, then orchestrates task execution with maximum parallelism:

// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],  // ^ means "all dependencies' build first"
      "inputs": ["src/**", "package.json", "tsconfig.json"],
      "outputs": ["dist/**", ".next/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "inputs": ["src/**", "tests/**"],
      "outputs": []
    },
    "lint": {
      "inputs": ["src/**", ".eslintrc*"],
      "outputs": []
    },
    "dev": {
      "persistent": true,
      "cache": false  // Never cache dev servers
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

With this config, turbo build will:

  • Build all packages in dependency order (topological sort)
  • Parallelize independent packages
  • Skip packages whose inputs (files) haven't changed (hash-based cache)
  • On cache hit: restore outputs from cache without re-running (milliseconds vs minutes)

Remote Caching with Vercel

Turborepo's killer feature is remote caching — sharing the build cache across your entire team and CI/CD pipeline. When developer A builds @acme/ui, the result is pushed to Vercel's remote cache. When developer B runs the same build with identical inputs, they get a cache hit and skip the build entirely.

# Link to Vercel remote cache
npx turbo login
npx turbo link

# Now every turbo run is potentially a cache hit from any team member's build
turbo build

# Output:
# @acme/ui:build: cache hit, replaying output...
# @acme/utils:build: cache hit, replaying output...
# @acme/web:build: >>> FULL TURBO  (all dependencies were cached)
# Tasks: 12 successful, 12 total
# Cached: 12 cached, 12 total
# Time: 847ms >>> FULL TURBO
Enter fullscreen mode Exit fullscreen mode

You can also self-host the remote cache using open-source alternatives like ducktape-cache or turborepo-remote-cache.

Turborepo Codebase Structure

my-monorepo/
├── apps/
│   ├── web/          # Next.js app
│   └── docs/         # Docusaurus site
├── packages/
│   ├── ui/           # Shared React components
│   ├── config/       # Shared configs (eslint, tsconfig)
│   └── utils/        # Shared utilities
├── turbo.json
└── package.json      # Workspace root with workspaces field
Enter fullscreen mode Exit fullscreen mode

When to Use Turborepo

Turborepo is ideal for application-focused monorepos where speed and simplicity are the priorities. If you're building a suite of Next.js apps with shared packages and want to set up a monorepo in 30 minutes with excellent Vercel deployment integration, Turborepo is the natural choice. Its minimal configuration surface means less to learn and maintain.

Nx: The Full-Featured Platform

Nx, developed by Nrwl, is the most feature-rich of the three tools. It goes well beyond task running to provide a full development platform: code generation, project graph visualization, automated migrations, and first-class integrations for React, Angular, Node.js, Next.js, and dozens of other frameworks.

How Nx Works

Nx builds a project graph by analyzing your source code — not just package.json imports, but actual TypeScript/JavaScript import statements. This means it understands dependencies even in non-npm-linked scenarios:

# nx.json
{
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "namedInputs": {
    "default": ["{projectRoot}/**/*", "sharedGlobals"],
    "production": [
      "default",
      "!{projectRoot}/**/*.spec.ts",
      "!{projectRoot}/jest.config.ts"
    ]
  },
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"],
      "cache": true
    },
    "test": {
      "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
      "cache": true
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The Project Graph

Run npx nx graph to open an interactive visualization of your entire monorepo's dependency graph. This is invaluable for understanding impact of changes:

# Show what's affected by changes since main branch
npx nx affected:graph

# Run only tests for affected projects
npx nx affected --target=test --base=main

# Run specific project's build
npx nx build my-app

# Run with task runner parallelism
npx nx run-many --target=build --all --parallel=4
Enter fullscreen mode Exit fullscreen mode

Nx Generators (Code Generation)

Nx's code generators (formerly called "schematics") are one of its most powerful differentiators. They automate creating consistent new apps, libraries, and components:

# Add a new React app to the monorepo
npx nx g @nx/react:app my-new-app

# Add a shared library
npx nx g @nx/react:lib ui-components --directory=shared

# Add a component to a library
npx nx g @nx/react:component Button --project=shared-ui-components

# Generate a Node.js API
npx nx g @nx/node:app my-api --framework=express
Enter fullscreen mode Exit fullscreen mode

Each generator creates files, updates imports, and registers the project in the workspace — ensuring consistent structure across your entire codebase without manual copy-pasting.

Nx Cloud: Remote Caching and Distributed Task Execution

Nx Cloud (the paid cloud offering) provides remote caching similar to Turborepo, plus Distributed Task Execution (DTE) — a unique feature that distributes CI tasks across multiple agents in parallel:

// In CI: distribute 50 test suites across 10 agents
npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js"
npx nx affected --target=test
npx nx-cloud stop-all-agents
Enter fullscreen mode Exit fullscreen mode

This can reduce a 30-minute CI run to 5 minutes by running tasks on 6 parallel agents. The free tier of Nx Cloud covers most small-to-medium teams.

When to Use Nx

Nx is best for large enterprise monorepos, teams that want strong conventions enforced by tooling, and mixed-technology workspaces (e.g., Angular frontends + Node.js backends + shared TypeScript libraries). Its generator ecosystem and migration tools ("Nx migrate") make upgrading framework versions (React 18 → 19, Next.js 14 → 15) much less painful.

Head-to-Head Comparison

Configuration Complexity

  • Turborepo: Minimal — one turbo.json with task definitions. New developers are productive in an hour.
  • Lerna: Minimal for publishing workflows, moderate for task orchestration.
  • Nx: High initial learning curve, but the investment pays off at scale. Deep configuration options for fine-grained control.

Caching

  • Turborepo: Excellent. Hash-based local + remote caching (Vercel or self-hosted). Dead simple to configure.
  • Lerna: Delegates to Nx when useNx: true. Standalone Lerna has basic task hashing.
  • Nx: Excellent. Sophisticated input/output tracking, remote caching via Nx Cloud, distributed execution.

Ecosystem and Framework Support

  • Turborepo: Framework-agnostic. Works with any build system. No code generation.
  • Lerna: Framework-agnostic. Publishing-focused.
  • Nx: Deep integrations for React, Angular, Vue, Next.js, Nest.js, Express, Fastify, Storybook, Cypress, Jest, Vite, and more.

Scalability

  • Turborepo: Scales well to hundreds of packages. Simpler mental model may become a limitation at Google/Meta scale.
  • Lerna: Scales to hundreds of packages for publishing; leans on Nx for performance at scale.
  • Nx: Battle-tested at thousands of packages. Distributed task execution handles the most extreme CI scenarios.

Migration Considerations

If you're converting an existing multi-repo setup to a monorepo, or migrating between tools:

  • To Turborepo: Add turbo.json, define task pipeline, run turbo build. Usually done in an afternoon.
  • To Nx: Run npx nx@latest init in an existing monorepo — Nx's init command auto-detects projects and generates configuration. Full migration can take days for large repos.
  • To Lerna: npx lerna init in a workspace root. Primary migration concern is configuring your versioning/publishing strategy.

Decision Guide

Choose Turborepo if:

  • You want to get started quickly with minimal configuration
  • You're deploying primarily to Vercel and want native integration
  • Your team is small to medium and prefers simplicity over features
  • You have application packages rather than published libraries

Choose Nx if:

  • You have a large team with diverse technology stacks
  • You want enforced conventions and code generation
  • CI times are a serious bottleneck and you need distributed execution
  • You're building on Angular, or a mix of Angular + React + Node

Choose Lerna if:

  • You're building an open-source library that publishes multiple npm packages
  • Conventional commits + automated changelog generation is a priority
  • You want Lerna's publishing workflow with Nx's performance under the hood

Conclusion

The monorepo tooling ecosystem has matured rapidly. Turborepo wins on simplicity and developer experience for application monorepos. Nx wins on features, scalability, and enterprise-grade tooling. Lerna wins specifically for publishing-focused open-source library repositories.

Notably, these tools aren't mutually exclusive — modern Lerna uses Nx internally, and you can run Turborepo alongside other tools. The most important choice is picking one and using it consistently across your team.

For more on JavaScript tooling decisions, see our comparisons of npm vs pnpm vs yarn and Vite vs Webpack.

Free Developer Tools

If you found this article helpful, check out DevToolkit — 40+ free browser-based developer tools with no signup required.

Popular tools: JSON Formatter · Regex Tester · JWT Decoder · Base64 Encoder

🛒 Get the DevToolkit Starter Kit on Gumroad — source code, deployment guide, and customization templates.

Top comments (0)