- We need to install Turborepo in our project by running
npm install turbo -Dto install it in the root of our project as adevDependency. - Then, we need to update
.gitignoreto preventgitto include certain folders in version control. In this case, we're going to ignore.turboand the output folders for all the applications in the monorepo,dist/**and.next/** - Create a
turbo.jsonfile and reference the Turborepo's JSON Schema
- Let's add the
pipelineobject in theturbo.jsonfile. - Select the scripts we want Turborepo to take care of from our
package.jsonfile, then. For instance, if we want Turborepo to run thedevcommand, we have to create a"dev"key inside the"pipeline"object inturbo.json. - We can try this out with the Turborepo CLI, we just need to run
npx turbo run [your pipeline name] - Make sure we add the
@monorepo/utilspackage as a dependency in the@monorepo/blogand@monorepo/dashboardprojects to avoid any dependency problems. For this we can use the commandnpm install @monorepo/utils -w=@monorepo/blog -w=@monorepo/dashboard. For more information, see this Egghead.io lesson Install dependencies for specific packages in a monorepo - We migrate all the commands that we care about as Turborepo pipelines.
-
dev->npx turbo run dev -
check->npx turbo run test typecheck -
test->npx turbo run test -
build->npx turbo run build -
typecheck->npx turbo run typecheck
- Let's replace all the scripts we have in the root
package.jsonwith their turborepo counterparts.
In some cases, you want to make sure that Turborepo is building the dependencies in a specific order, for example, we always want to build the @monorepo/utils first, before building the @monorepo/dashboard and @monorepo/blog projects. For that, we have to add the "dependsOn" key to the pipeline we want to behave like that.
"build": {
+ "dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},In some other cases where you need more granular control over what to build first in different projects you can do the following:
Turborepo is already taking care of building things in the right order because @monorep/utils is a dependency of @monorepo/dashboard and @monorepo/blog and that we're already specifying that @monorepo/dashboard and @monorepo/blog depend on the build step from @monorepo/utils to succeed. All that said, for this lesson we're going to remove the @monorepo/utils dependencies from @monorepo/dashboard and @monorepo/blog, then we delete the build artifacts from @monorepo/utils (the dist folder), and finally we'll run npm install. Once that's done we're going to run npm run build and we'll see that we have a problem with our build because we're building things "out of sync", that means that there's no way for Turborepo to tell which project to build first since we don't specify that @monorepo/utils is a dependency of @monorepo/blog and @monorepo/dashboard.
The way to fix this would be to define a pipeline for both projects @monorepo/dashboard and @monorepo/blog.
With this we're telling Turborepo to always run the @monorepo/utils project, before running the build command in @monorepo/dashboard and @monorepo/blog
In the package.json file of @monorepo/dashboard and @monorepo/blog
All the patch for this lesson can be found in the /patches/lesson-03.patch file.
"dependencies": {
- "@monorepo/utils": "^1.0.0",In turbo.json
"pipeline": {
+ "@monorepo/dashboard#build": {
+ "dependsOn": ["@monorepo/utils#build"]
+ },
+ "@monorepo/blog#build": {
+ "dependsOn": ["@monorepo/utils#build"]
+ },For this we need to install Graphviz first. Once we have that installed, we can run npx turbo run [pipeline to inspect] --graph=name-of-the-graph.{svg|jpg|json|pdf|png|html} and it will generate the file you specified for you. I found this to be useful to understand how your projects depend on each other.
We already have a few npm scripts that are not using Turborepo, instead they are using raw npm scripts, like npm run typecheck -w @monorepo/dashboard.
In order to tell Turborepo to run just in certain projects, we need to use the --filter flag.
Official --filter documentation
To test out the filters we will use the patch that's in patches/lesson-05-filter-command.patch, lets:
git checkout -b lesson-5You can name your branch whatever you want.git apply patches/lesson-05-filter-command.patch- Start filtering out
- By package
- By dependants
- By dependencies
- Exclude
- Git changed packages
Now, let's update the npm scripts we have in our root package.json file
Turborepo will terminate the process it's running if it encounters an error, we can prevent this from happening if we pass the --continue=true flag to the Turborepo command we want to execute.
npx turbo run test --continue=true- Make the tests in
utils/to fail - Run
npx turbo run test - See what happens
- Add the
--continue=trueflag to thenpx turbo run testcommand
I have found this to be useful when I want to know the impact of my changes across the whole project. Given the fact that @monorepo/utils is a dependency of @monorepo/dashboard and @monorepo/blog it's important to know the impact of my changes not only in the @monorepo/utils package, but in the packages that use it.
We can bypass Turborepo's local (and remote) cache if we need to. This will run the command you specify like it was the first time you run it. I have found this useful in development mode and when I'm trying to debug something inside a package and I want to be 100% sure that I'm getting the latest version of my changes.
npx turbo run test --forceYou can also clear your local cache by deleting the node_modules/.cache/turbo folder.
rm -rf node_modules/.cache/.turboOne strategy that I've found useful is to use the graph generated by the --graph command, plus, the --dry command. It will give you a nice output telling you what's going on whenever you run the command. Let's take the build command as an example
npx turbo run build --dry=jsonAnd it will give you a nice JSON output, I'd pay special attention to the packages, dependencies, and dependents keys.
{
"packages": ["@monorepo/blog", "@monorepo/dashboard", "@monorepo/utils"],
"tasks": [
{
"taskId": "@monorepo/utils#build",
"task": "build",
"package": "@monorepo/utils",
"hash": "998cbe802d4e6ec4",
"command": "tsup",
"outputs": [".next/**", "dist/**"],
"logFile": "libs/utils/.turbo/turbo-build.log",
"directory": "libs/utils",
"dependencies": [],
"dependents": ["@monorepo/blog#build", "@monorepo/dashboard#build"]
},
{
"taskId": "@monorepo/blog#build",
"task": "build",
"package": "@monorepo/blog",
"hash": "e9f89b69796ea268",
"command": "next build",
"outputs": [".next/**", "dist/**"],
"logFile": "apps/blog/.turbo/turbo-build.log",
"directory": "apps/blog",
"dependencies": ["@monorepo/utils#build"],
"dependents": []
},
{
"taskId": "@monorepo/dashboard#build",
"task": "build",
"package": "@monorepo/dashboard",
"hash": "2c8a4a51bbd1fb7d",
"command": "tsc \u0026\u0026 vite build",
"outputs": [".next/**", "dist/**"],
"logFile": "apps/dashboard/.turbo/turbo-build.log",
"directory": "apps/dashboard",
"dependencies": ["@monorepo/utils#build"],
"dependents": []
}
]
}I've found this useful specially in CI, there I just want to see the logs of the packages that have changed instead of the logs for everything. We can choose the level of detail of our logs by passing a value to the --output-logs flag, it could either be full or new-only
npx turbo run build --output-logs=new-onlySo far, our cache only works locally - it lives inside node_modules/.cache/turbo, and that means that we can't share the cache between machines. The problem that remote caching solves is exactly that, being able to share the cache between machines.
npx turbo login
npx turbo linkLet's run npx turbo run test, delete the turbo cache directory rm -rf node_modules/.cache/turbo and then let's run npx turbo run test, you'll see that we're getting the cached version from Turborepo's Remote Cache that's hosted on Vercel.
You can even take a look at your usage in this tab in your Vercel dashboard. https://vercel.com/dashboard/usage
Another way to test that remote caching is working is to use the --remote-only flag to ignore the local cache.
