We all start our first steps in software engineering with small projects. Over time, our projects become larger and more complex. This is where the new architecture of the monorepo project comes into play. There are many tools for developing monorepo projects but in this guide, we will focus on Turborepo and its recent v2 release.
Turborepo, developed by Vercel, is a popular tool for creating monorepos in the JavaScript/Typescript ecosystem. It is powerful, fast, and easy to use, whether you want to install it or add it to an existing project.
If you are new to Turborepo and want a deeper dive, check out LogRocket’s guide to building a full-stack TypeScript application with Turborepo.
Recently, the Turborepo team introduced new core features in version 2.0. These features include:
In previous versions of Turborepo, when we were working on both libraries and apps simultaneously, we had to read a large amount of log information in one place. Now, starting with version 2.0, we can select specific tasks — whether for a library or an app — and explore their logs individually. This makes it easier to focus and read.
Additionally, in previous versions of Turborepo, we could not interact with the script to execute commands, although many other monorepo tools allowed this. Now we can do this by typing to our scripts via stdin
, and entering data directly into the interface. This allows us to run specific test suites using Jest, perform database migrations, and much more.
To make the task interactive, we can update the turbo.json
file by adding "persistent": true
for the specific task:
{ "tasks": { "dev": { "cache": false, "persistent": true // add and make the task interactive } } }
Then we can select the task in the terminal UI and press Enter
to enter the task shell and CTRL+Z
to exit.
Turborepo can run many tasks at the same time, which helps us work faster. However, starting with version 2.0, we can get the most out of Turborepo’s parallelization by using the “watcher” feature that allows us to re-run our code whenever we change something in our source code. Many tools don’t do this or don’t support monorepos, which leads to problems with scripts that depend on other scripts in our repository.
Let’s demonstrate how we can use it easily:
turbo watch dev lint test
Now Turborepo will re-run tasks whenever we make changes to our code using the configuration from turbo.json
.
The Turborepo team has released updated documentation based on the strengths of previous versions and user feedback. They now offer:
One of the main reasons Turborepo stands out as a monorepo tool is its use of caching. Turborepo uses caching to speed up the development process and prevent doing the same work repeatedly. Turborepo caching saves a lot of time when working locally, and when combined with remote caching, it becomes even more powerful by sharing the cache across the entire team.
We can try to get our first cache by creating a Turborepo project with the following command:
npx create-turbo@latest // npm pnpm dlx create-turbo@latest // pnpm
Now, let’s run the build
script in package.json
, which triggers a turbo build
:
npm run build
This will result in a cache miss because we have never run the previous build
script before with this input set in this repository:
If we run turbo build
again, we get the following result:
Turborepo stores the results of tasks in the .turbo/cache
directory and can share the cache with our teammates and CI to speed up work.
To use it, we need to authenticate with our remote cache provider using the following command:
npx turbo login // npm
Then, link the repository on our machine:
npx turbo link // npm
Now, when we run a task, Turborepo will automatically send the task’s output to the remote cache. The next time the same task is run on any machine authentication with the remote cache, it will retrieve the cached result on the first run.
Now, to get a good understanding of the new features in Turborepo 2.0, let’s create our first monorepo project using a basic starter example.
I will first create a monorepo project using Turborepo:
npx create-turbo@latest // npm pnpm dlx create-turbo@latest // pnpm
This will prompt us for our project name and to select the package manager we want to use:
And voilĂ , we have just created our monorepo project using Turborepo! Our project includes the following packages/apps:
docs
: A documentation Next.js app exampleweb
: A web Next.js app example@repo/ui
: React component library for web
and docs
apps@repo/eslint-config
: Common eslint
configurations for libraries and apps@repo/typescript-config
: tsconfig.json
for libraries and appsOur turbo.json
file is set up as follows:
{ "$schema": "https://turbo.build/schema.json", "ui": "tui", "tasks": { "build": { "dependsOn": ["^build"], "inputs": ["$TURBO_DEFAULT$", ".env*"], "outputs": [".next/**", "!.next/cache/**"] }, "lint": { "dependsOn": ["^lint"] }, "dev": { "cache": false, "persistent": true } } }
Above, we set a specific URL schema for our Turbo configuration. We also defined ui
as tui
to format the terminal UI. Then, we specified the build
, lint
, and dev
tasks.
Next, we will run all apps with the following command:
pnpm run dev
It runs dev
scripts in all app package.json
files and opens them in a new terminal with tasks:
As we see above, we have two tasks on the left side of the terminal, and task details on the main content of the terminal window. If we navigate to the local URL, we will see more output logs, details about web app states, requests, and more. By switching between tasks, we can examine each detail separately by task content. This is an incredibly useful feature and makes it easier to understand while we are working on a specific app or package.
Lastly, we are going to test the new Watch Mode feature in our Turborepo project. Let’s run all of our tasks with the following command:
turbo watch dev lint
Now, we can see all the tasks on the left sidebar. If we navigate to web#lint
task, we can see lint run once:
If we change anything in the source code of the web app, the lint
task will be re-run like turbo run
:
This is a very useful feature to speed up our work.
There are many tools available for working with monorepos, such as Lerna, Nx, and Bazel, each with its own strengths and weaknesses. Some are designed specifically for the frontend, backend, or both, while others excel in large projects or focus mainly on TypeScript.
But Turborepo stands out for its emphasis on speed, caching and parallelization, ease of use, and its efficiency when working with both small and large projects. It also has a large community of users. There are many reasons why you should use Turborepo, especially given the Turborepo 2.0 release.
Thanks for reading. I hope you found this piece useful. Happy coding!
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowEfficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
Design React Native UIs that look great on any device by using adaptive layouts, responsive scaling, and platform-specific tools.
Angular’s two-way data binding has evolved with signals, offering improved performance, simpler syntax, and better type inference.
Fix sticky positioning issues in CSS, from missing offsets to overflow conflicts in flex, grid, and container height constraints.