Constructing CI
Turborepo speeds up builds, lints, tests, and any other tasks that you need to do in your Continuous Integration pipelines. Through parallelization and Remote Caching, Turborepo makes your CI dramatically faster.
For examples of how to connect your CI vendor to Remote Cache and run tasks, visit our CI guides.
Enabling Remote Caching
To enable Remote Caching for your CI, setup the environment variables for Turborepo to access your Remote Cache.
Environment Variable | Description |
---|---|
TURBO_TOKEN | The Bearer token to access the Remote Cache |
TURBO_TEAM | The account name associated with your repository |
When you run tasks through turbo
, your CI will be able to hit cache, speeding up your pipelines.
Remote Cache hosting
Vercel's built-in CI/CD is automatically connected to your managed Vercel Remote Cache with zero configuration. To retrieve a token for connecting your other CI vendors to Vercel Remote Cache, visit the Vercel Remote Cache documentation.
For self-hosted Remote Cache options, visit Turborepo's Remote Cache documentation.
Running tasks in CI
By installing turbo
globally onto your development and CI machines, you can use one mental model to run your entire repository, from development to ship. The tasks that you've registered in your turbo.json
will work exactly the same in CI.
- For more information on how to set up tasks, visit the Configuring Tasks page.
- For examples of running tasks in CI, visit our CI guides.
Filtering for entry points
You can filter your tasks using the --filter
flag exactly the same as when you're working with turbo
locally. Filtering by packages, directories, and Git history are all supported in CI.
Using Git history in CI
Filtering using source control changes is only possible when history is available on the machine. If you are using shallow clones, history will not be available.
You can also use the --affected
flag to only run tasks in packages that have changes.
Docker
Docker is an important part of many deployment pipelines. Turborepo's prune
subcommand helps you ship lightweight images by removing unnecessary dependencies and code from your images.
For more on how to deploy from a Turborepo with Docker, visit the dedicated Docker guide.
Skipping tasks and other unnecessary work
Running only affected tasks
You can use the --affected
flag to only run tasks that have changes.
You'll want to use this flag in situations like:
- You're running many tasks across packages in your monorepo, and only want to run those tasks in packages with code changes.
- You’re not using a Remote Cache, but still want to do as little work as possible in CI.
- You are using a Remote Cache, and you’re in a large repository. By minimizing the amount of tasks that will be restored from cache, there will be less data to send across the network, resulting in faster cache restoration.
- You’re already using advanced filtering techniques or
turbo-ignore
to create the same or similar behavior as--affected
. You likely have the opportunity to simplify your scripting using this new flag.--affected
will can handle shallow clones more gracefully than bespoke filtering because it falls back to running all tasks.
Using --affected
in GitHub Actions
CI/CD pipelines are a perfect place to use --affected
. With --affected
, Turborepo can automatically detect that you're running in GitHub Actions by inspecting environment variables set by GitHub, like GITHUB_BASE_REF
.
In the context of a PR, this means that Turborepo can determine which packages have changed between the PR's base branch and the PR's head branch. This allows you to run only the tasks that are affected by the changes in the PR.
While GITHUB_BASE_REF
works well in pull_request
and pull_request_target
events, it is not available during regular push events. In those cases, we use GITHUB_EVENT_PATH
to determine the base branch to compare your commit to. In force pushes and pushing branch with no additionals commits, we compare to the parent of the first commit on the branch.
Using turbo-ignore
As your codebase and CI grow, you may start to look for more ways to get even faster. While hitting cache is useful, you also may be able to skip work entirely. Using turbo-ignore
, you can skip lengthy container preparation steps like dependency installation that will end up resulting in a cache hit, anyway.
Checkout the repository
Start by cloning your repository. Note that a clone with history to the cloning depth you plan on using is necessary for comparisons.
Good to know:
By default, turbo-ignore
uses the parent commit. To customize for more
depth, see the turbo-ignore reference.
Run turbo-ignore
for the package and task
By default, turbo-ignore
will use the build
task in the current working directory.
- To check for changes to a different task, use the
--task
flag. - To check for changes for a specific package and its dependencies, add the package's name as an argument.
Check for changes for the build
task for the web
package and its dependencies by adding the web
package as an argument:
Handle the result
If changes are detected in the package or its Internal Dependencies, turbo
will exit with a 1
status code. If no changes are detected, it will exit with 0
.
Using this status code, you can choose what the rest of your CI pipeline should do. For instance, a 1
exit code likely means that you should move forward with installing dependencies and running tasks.
For more advanced use cases, see the turbo-ignore
reference.
Best practices
Rely on caching
Turborepo's caching abilities allow you to create fast CI pipelines with minimal complexity. Through Remote Caching and using the --filter
flag to target packages for builds, Turborepo will handle change detection for large monorepos with little overhead.
For example, your CI could run these two commands to quickly handle quality checks and build your target application:
turbo run lint check-types test
: Run quality checks for your entire repository. Any packages that haven't changed will hit cache.turbo build --filter=web
: Build theweb
package using thebuild
task you've registered inturbo.json
. If theweb
package or its dependencies haven't changed, the build will also hit cache.
As your codebase scales, you may find more specific opportunities to optimize your CI - but relying on caching is a great place to start.
Global turbo
in CI
Using global turbo
is convenient in CI workflows, allowing you to easily run commands specific to your CI and take advantage of Automatic Workspace Scoping.
However, in some cases, you may be running turbo
commands or scripts that use turbo
before installing packages with your package manager. One example of this is using turbo prune
to create a Docker image. In this situation, global turbo
will not be able to use the version from package.json
because the binary for that version hasn't been installed yet.
For this reason, we encourage you to pin your global installation of turbo
in CI to the major version in package.json
since breaking changes will not be introduced within a major version. You could additionally opt for added stability by pinning an exact version, trading off for maintenance burden to receive bug fixes in patch releases.
Use turbo run
in CI
turbo run
is the most common command you will use when working in your Turborepo so it is aliased to turbo
for convenience. While this is great for working locally, there are other subcommands for turbo
like turbo prune
and turbo generate
.
We're always working to make turbo
better so we may add more subcommands in the future. For this reason, you can prevent naming collisions by using turbo run
in your CI.
As an example, if you have a turbo deploy
command in your CI pipelines, it may conflict with a potential deploy
subcommand built directly into the turbo
CLI. To avoid this, use turbo run deploy
in your CI pipeline instead.
Troubleshooting
Hitting cache results in broken builds
If your task is passing when you miss cache but failing when you hit cache, you likely haven't configured the outputs
key for your task correctly.
Deployment using the wrong environment variables
If you haven't defined the env
or globalEnv
keys for your task, Turborepo will not be able to use them when creating hashes. This means your task can hit cache despite being in a different environment.
Check your configuration for the env
and globalEnv
keys.
Next steps
You now have everything you need to ship applications with Turborepo. To learn more about specific use cases, check the Guides or dive deeper into core concepts.
Was this helpful?