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....
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.