Turborepo

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 VariableDescription
TURBO_TOKENThe Bearer token to access the Remote Cache
TURBO_TEAMThe 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.

Terminal
turbo run build --affected

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:

Terminal
npx turbo-ignore web

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 the web package using the build task you've registered in turbo.json. If the web 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.

hours

Total Compute Saved
Get started with
Remote Caching →

On this page