Docs
Guides
Migrate from Lerna

Using with Lerna

Turborepo and Lerna have a lot a in common, but also some key differences.

tl;dr you can use Lerna and Turbo together.

  • Use lerna symlinking (lerna bootstrap) packages, publishing and changelog generation
  • Use turbo for task running and caching

Tool Comparison

Lerna is a monorepo task runner and npm workspace implementation. Both Turborepo and Lerna can be used to run tasks across packages in parallel and also topologically (i.e. if A depends on B, run B before A).

Caching

However, unlike Turborepo, Lerna has no ability to cache prior work or intelligently schedule tasks (i.e. create pipelines).

Task Scheduling

Turborepo's task scheduler is more powerful than Lerna's (which can only schedule one task at a time) thanks to Turborepo pipelines. Turborepo reduces idle CPUs, saves compute resource, and collapse waterfalls—which ultimately results in faster overall builds.

Let's look at an example. Imagine you have two packages A and B each with 3 tasks build, test, and bundle, where A depends on B being built....

Turborepo vs. Lerna Task Execution

The above may not not look like much. But imagine that A's build task takes 20 minutes and now look at when B's tests run. Woah....yeah....scheduling can save insane amounts of time when you have long build times.

Package Publishing, Versioning, and Changelog Generation

Lerna can version and publish packages to npm registries as well as create changelogs. It's extremely good at this, especially for releasing canary pre-releases. While Turborepo may eventually tackle these features, at the time of writing, it is not a high priority goal (we suggest using Changesets in the meantime). If Changesets isn't for you, and you want to stick with Lerna's publish flow, you can use Lerna and Turborepo together.

Example migration

Say you have a Lerna-powered monorepo setup like so:

// lerna.json
{
  "npmClient": "yarn",
  "packages": ["packages/*"],
  "command": {
    "version": {
      "exact": true
    },
    "publish": {
      "npmClient": "npm",
      "allowBranch": ["master", "canary"],
      "registry": "https://registry.npmjs.org/"
    }
  },
  "version": "2.1.6"
}
{
  "private": true,
  "scripts": {
    "dev": "lerna run dev --stream --parallel",
    "test": "lerna run test",
    "build": "lerna run build",
    "prepublish": "lerna run prepublish",
    "publish-canary": "lerna version prerelease --preid canary --force-publish",
    "publish-stable": "lerna version --force-publish && release && node ./scripts/release-notes.js"
  },
  "devDependencies": {
    "lerna": "^3.19.0"
  }
}

To add turbo, run the following command in your terminal

yarn add turbo --dev -W

Alter package.json to use turbo for task running, but keep lerna for versioning.

{
  "private": true,
  "scripts": {
-   "dev": "lerna run dev --stream --parallel",
+   "dev": "turbo run dev --parallel --no-cache",
-   "test": "lerna run test",
+   "test": "turbo run test",
-   "build": "lerna run build",
+   "build": "turbo run build",
    "prepublish": "lerna run prepublish",
    "publish-canary": "lerna version prerelease --preid canary --force-publish",
    "publish-stable": "lerna version --force-publish && release && node ./scripts/release-notes.js"
  },
  "devDependencies": {
    "lerna": "^3.19.0",
+   "turbo": "latest"
  }
}

Create a turbo.json file in the root of your project.

{
  "$schema": "https://turborepo.org/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "outputs": []
    },
    "dev": {
      "cache": false
    }
  }
}

If you're not using yarn or npm workspaces with Lerna, you should keep around your lerna bootstrap command if you have one. Turborepo considers Lerna a valid workspace implementation. Everything should work as expected.

Last updated on April 28, 2022