file: ./content/repo-docs/index.mdx
meta: {
"title": "Introduction",
"description": "Welcome to the Turborepo documentation!"
}
Welcome to the Turborepo documentation!
***
## What is Turborepo?
Turborepo is a high-performance build system for JavaScript and TypeScript codebases. It is designed for scaling monorepos and also makes workflows in [single-package workspaces](/repo/docs/guides/single-package-workspaces) faster, too.
From individual developers to the largest enterprise engineering organizations in the world, Turborepo is saving years of engineering time and millions of dollars in compute costs through a lightweight approach to optimizing the tasks you need to run in your repository.
## The monorepo problem
Monorepos have many advantages - but **they struggle to scale**. Each workspace has its own test suite, its own linting, and its own build process. A single monorepo might have **thousands of tasks to execute**.

These slowdowns can dramatically affect the way your teams build software, especially at scale. Feedback loops need to be fast so developers can deliver high-quality code quickly.
## The monorepo solution

**Turborepo solves your monorepo's scaling problem**. [Remote Cache](/repo/docs/core-concepts/remote-caching) stores the result of all your tasks, meaning that **your CI never needs to do the same work twice**.
Additionally, task scheduling can be difficult in a monorepo. You may need to build, *then* test, *then* lint...
Turborepo **schedules your tasks for maximum speed**, parallelizing work across all available cores.
Turborepo can be **adopted incrementally** and you can **add it to any repository in just a few minutes**. It uses the `package.json` scripts you've already written, the dependencies you've already declared, and a single `turbo.json` file. You can **use it with any package manager**, like `npm`, `yarn` or `pnpm` since Turborepo leans on the conventions of the npm ecosystem.
## How to use these docs
We will do our best to keep jargon to a minimum - but there are some need-to-know words that will be important to understand as you read through the docs. We've created [a glossary page](https://vercel.com/docs/vercel-platform/glossary) to help you out in case you're learning about these terms.
## Join the community
If you have questions about anything related to Turborepo, you're always welcome to ask the community on [GitHub Discussions](https://github.com/vercel/turborepo/discussions), [Vercel Community](https://vercel.community/tag/turborepo), and [Twitter](https://twitter.com/turborepo).
file: ./content/repo-docs/core-concepts/index.mdx
meta: {
"title": "Core concepts",
"description": "Learn about the core concepts behind Turborepo."
}
import { Card, Cards } from '#/components/card';
Learn more about the core concepts of Turborepo:
file: ./content/repo-docs/core-concepts/internal-packages.mdx
meta: {
"title": "Internal Packages",
"description": "Learn how to build Internal Packages in your monorepo."
}
import { PackageManagerTabs, Tab } from '#/components/tabs';
Internal Packages are libraries whose source code is inside your Workspace. You can quickly make Internal Packages to share code within your monorepo and choose to [publish them to the npm registry](/repo/docs/guides/publishing-libraries) if you need to later.
Internal Packages are used in your repository by installing them in `package.json` similar to an external package coming from the npm registry. However, instead of marking a version to install, you can reference the package using your package manager's workspace installation syntax:
```json title="./apps/web/package.json"
{
"dependencies": {
"@repo/ui": "*" // [!code highlight]
}
}
```
```json title="./apps/web/package.json"
{
"dependencies": {
"@repo/ui": "*" // [!code highlight]
}
}
```
```json title="./apps/web/package.json"
{
"dependencies": {
"@repo/ui": "workspace:*" // [!code highlight]
}
}
```
In the [Creating an Internal Package guide](/repo/docs/crafting-your-repository/creating-an-internal-package), you can build an Internal Package from the beginning using [the Compiled Package strategy](#compiled-packages). On this page, we'll describe other strategies for creating Internal Packages and their tradeoffs, including [publishing the package to the npm registry](#publishable-packages) to create an External Package.
You can then import the package into your code like you're used to doing with an external package:
```tsx title="./apps/web/app/page.tsx"
import { Button } from '@repo/ui'; // [!code highlight]
export default function Page() {
return ;
}
```
## Compilation Strategies
Depending on what you need from your library, you can choose one of three compilation strategies:
* [**Just-in-Time Packages**](#just-in-time-packages): Create minimal configuration for your package by allowing application bundlers to compile the package as it uses it.
* [**Compiled Packages**](#compiled-packages): With a moderate amount of configuration, compile your package using a build tool like `tsc` or a bundler.
* [**Publishable Packages**](#publishable-packages): Compile and prepare a package to publish to the npm registry. This approach requires the most configuration.
### Just-in-Time Packages
A Just-in-Time package is compiled by the application that uses it. This means you can use your TypeScript (or uncompiled JavaScript) files directly, requiring much less configuration than the other strategies on this page.
This strategy is most useful when:
* Your applications are built using a modern bundler like Turbopack, webpack, or Vite.
* You want to avoid configuration and setup steps.
* You're satisfied with your applications' build times, even when you can't hit cache for the package.
A `package.json` for a Just-in-Time package may look like this one:
```json title="./packages/ui/package.json"
{
"name": "@repo/ui",
"exports": {
"./button": "./src/button.tsx", // [!code highlight]
"./card": "./src/card.tsx" // [!code highlight]
},
"scripts": {
"lint": "eslint . --max-warnings 0", // [!code highlight]
"check-types": "tsc --noEmit" // [!code highlight]
}
}
```
There are a few important things to notice in this `package.json`:
* **Directly exporting TypeScript**: The `exports` field marks the entrypoints for the package and, in this case, you're **referencing TypeScript files directly**. This is possible because the bundler for the application will compile the code as it uses it in its build process.
* **No `build` script**: Because this package is exporting TypeScript, it doesn't need a build step for transpiling the package. This means you don't have to configure a build tool in this package to make it work in your Workspace.
#### Limitations and tradeoffs
* **Only applicable when consumers do transpiling**: This strategy can only be used when the package is going to be used in tooling that uses a bundler or natively understands TypeScript. The consumer's bundler is responsible for transpiling the TypeScript packages to JavaScript. If your builds or other usages of the package are not able to consume TypeScript, you will need to move to the [Compiled Packages](#compiled-packages) strategy.
* **No TypeScript `paths`**: A library that is being transpiled by its consumer cannot use the `compilerOptions.paths` configuration because TypeScript assumes that source code is being transpiled in the package where it is written. If you're using TypeScript 5.4 or later, we recommend [using Node.js subpath imports](https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/#auto-import-support-for-subpath-imports). To learn how, visit [our TypeScript page](/repo/docs/guides/tools/typescript#use-nodejs-subpath-imports-instead-of-typescript-compiler-paths).
* **Turborepo cannot cache a build for a Just-in-Time Package**: Because the package doesn't have its own `build` step, it can't be cached by Turborepo. This tradeoff may make sense for you if you want to keep configuration to a minimum and are okay with the build times for your applications.
* **Errors in internal dependencies will be reported**: When directly exporting TypeScript, type-checking in a dependent package will fail if code in an internal dependency has TypeScript errors. You may find this confusing or problematic in some situations.
### Compiled Packages
A Compiled Package is a package that handles its own compilation using a build tool, like [`tsc` (the TypeScript compiler)](https://www.typescriptlang.org/docs/handbook/compiler-options.html#handbook-content).
```json title="./packages/ui/package.json"
{
"name": "@repo/ui",
"exports": {
"./button": {
"types": "./src/button.tsx", // [!code highlight]
"default": "./dist/button.js" // [!code highlight]
},
"./card": {
"types": "./src/card.tsx", // [!code highlight]
"default": "./dist/card.js" // [!code highlight]
}
},
"scripts": {
"build": "tsc" // [!code highlight]
}
}
```
Compiling your library produces compiled JavaScript outputs into a directory (`dist`, `build`, etc.) that you will use for the entrypoints for your package. The build outputs will be cached by Turborepo once they're added to the [`outputs` key of the task](/repo/docs/reference/configuration#outputs), allowing you to have faster build times.
#### Limitations and tradeoffs
* **Using the TypeScript compiler**: The majority of Compiled Packages should use `tsc`. Since the package is highly likely to be consumed by an application that is using a bundler, the application's bundler will prepare the library package for distribution in the application's final bundles, handling polyfilling, downleveling, and other concerns. A bundler should only be used if you have a specific use case that requires it, like bundling static assets into your package's outputs.
* **More configuration**: Compiled Packages require deeper knowledge and configuration to create build outputs. There are [many configurations for the TypeScript compiler](https://www.typescriptlang.org/docs/handbook/compiler-options.html#compiler-options) that can be difficult to manage and understand, and further configuration to optimize for bundlers, like [the `sideEffects` key in `package.json`](https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free). You can find some of our recommendations in [our dedicated TypeScript guide](/repo/docs/guides/tools/typescript).
### Publishable packages
Publishing a package to the npm registry comes with the most strict requirements of the packaging strategies on this page. Because you don't know anything about how your package will be used by consumers who download the package from the registry, you may find it difficult due to the numerous configurations required for a robust package.
Additionally, the process of publishing a package to the npm registry requires specialized knowledge and tooling. We recommend [`changesets`](https://github.com/changesets/changesets) for managing versioning, changelogs, and the publishing process.
For a detailed guide, visit [our Publishing packages guide](/repo/docs/guides/publishing-libraries).
file: ./content/repo-docs/core-concepts/package-and-task-graph.mdx
meta: {
"title": "Package and Task Graphs",
"description": "Turborepo builds a Task Graph based on your configuration and repository structure."
}
import { File, Folder, Files } from '#/components/files';
import { Callout } from '#/components/callout';
## Package Graph
The Package Graph is the structure of your monorepo created by your package manager. When you install [Internal Packages](/repo/docs/core-concepts/internal-packages) into each other, Turborepo will automatically identify those dependency relationships to build a foundational understanding of your Workspace.
This sets the groundwork for the Task Graph, where you'll define how **tasks** relate to each other.
## Task Graph
In `turbo.json`, you express how tasks relate to each other. You can think of these relationships as
dependencies between tasks, but we have a more formal name for them: the Task Graph.
You can generate a visualization of the task graph for your tasks using [the
`--graph` flag](/repo/docs/reference/run#--graph-file-type).
Turborepo uses a data structure called a [directed acyclic graph (DAG)](https://en.wikipedia.org/wiki/Directed_acyclic_graph) to
understand your repository and its tasks. A graph is made up of "nodes" and
"edges". In the Task Graph, the nodes are tasks and the edges are the
dependencies between tasks. A *directed* graph indicates that the edges
connecting each node have a direction, so if Task A points to Task B, we can say
that Task A depends on Task B. The direction of the edge depends on which task
depends on which.
For example, let's say you have a monorepo with an application in `./apps/web` that
depends on two packages: `@repo/ui` and `@repo/utils`:
You also have a `build` task that depends on `^build`:
```json title="./turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["^build"]
}
}
}
```
Turborepo will build a task graph like this:

### Transit Nodes
A challenge when building a Task Graph is handling nested dependencies. For
example, let's say your monorepo has a `docs` app that depends on the `ui`
package, which depends on the `core` package:
Let's assume the `docs` app and the `core` package each have a `build` task, but
the `ui` package does not. You also have a `turbo.json` that configures the
`build` task the same way as above with `"dependsOn": ["^build"]`. When you run
`turbo run build`, what would you expect to happen?
Turborepo will build this Task Graph:

You can think of this graph in a series of steps:
* The `docs` app only depends on `ui`.
* The `ui` package does **not** have a build script.
* The `ui` package's *dependencies* have a `build` script, so the task graph knows to include those.
Turborepo calls the `ui` package a Transit Node in this scenario, because it
doesn't have its own `build` script. Since it doesn't have a `build` script,
Turborepo won't execute anything for it, but it's still part of the graph for
the purpose of including its own dependencies.
#### Transit Nodes as entry points
What if the `docs/` package didn't implement the `build` task? What would
you expect to happen in this case? Should the `ui` and `core` packages still
execute their build tasks? Should *anything* happen here?
Turborepo's mental model is that all nodes in the Task Graph are the same. In other words,
Transit Nodes are included in the graph regardless of where they appear in the graph.
This model can have unexpected consequences. For example, let's say you've configured
your `build` task to depend on `^test`:
```json title="./turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["^test"]
}
}
}
```
Let's say your monorepo has many apps and many packages. All packages have
`test` tasks, but only one app has a `build` task. Turborepo's mental model
says that when you run `turbo run build`, even if an app doesn't implement `build`
the `test` task of all packages that are dependencies will show up in the graph.
file: ./content/repo-docs/core-concepts/package-types.mdx
meta: {
"title": "Package types",
"description": "Learn about the different types of packages in a workspace."
}
import { Callout } from '#/components/callout';
In Turborepo, we talk about two types of packages:
* [Application Packages](#application-packages)
* [Library Packages](#library-packages)
## Application Packages
An Application Package is a package in your workspace that will be deployed from your workspace. Examples of Application Packages are Next.js, Svelte, Vite, or CLI applications that are commonly found in the `./apps` directory.
It's best practice that your Application Packages are the "end" of your [Package Graph](/repo/docs/core-concepts/package-and-task-graph#package-graph), not being installed into other packages of your repository. Your CI/CD pipelines will most often finalize at these nodes of your Package and Task Graphs.
### Installing an application package into another package
In rare cases, you may need to install an Application Package into another package. This should be the exception. If you find you are doing this often, you may want to rethink your package structure.
An example of an exception for this rule is installing your Application Package into a package that handles end-to-end testing. Once installed, you can depend on the Application Package in your end-to-end testing package so it is aware of re-deploys of the application.
## Library Packages
Library Packages contain code that you intend to share around your workspace. They aren't independently deployable. Instead, they support the Application Packages to create the final deployables from your repository. You might also refer to these packages as [Internal Packages](/repo/docs/core-concepts/internal-packages), which have their own sub-types.
file: ./content/repo-docs/core-concepts/remote-caching.mdx
meta: {
"title": "Remote Caching",
"description": "Share cache artifacts across machines for even faster builds."
}
import { Callout } from '#/components/callout';
import { PlatformTabs, PackageManagerTabs, Tab } from '#/components/tabs';
import { ThemeAwareImage } from '#/components/theme-aware-image';
Turborepo's [task cache](/repo/docs/crafting-your-repository/caching) saves time by never doing the same work twice.
But there's a problem: **the cache is local to your machine**. When you're working with a Continuous Integration system, this can result in a lot of duplicated work:
Since Turborepo only caches to the local filesystem by default, the same task (`turbo run build`) must be **re-executed on each machine** (by you, by your teammates, by your CI, by your PaaS, etc.) even when all of the task inputs are identical — which **wastes time and resources**.
You don't have to use Remote Caching to use Turborepo. While Remote Caching
will bring the most significant speedups, you can make your existing workflows
faster without Remote Caching, too.
## A single, shared cache
What if you could share a single Turborepo cache across your entire team (and even your CI)?
Turborepo can securely communicate with a remote cache - a cloud server that stores the results of your tasks. This can save enormous amounts of time by **preventing duplicated work across your entire organization**.
Remote Caching is free and can be used with both [managed providers](https://turbo.build/repo/docs/core-concepts/remote-caching#managed-remote-cache-with-vercel) or as a [self-hosted cache](https://turbo.build/repo/docs/core-concepts/remote-caching#self-hosting).
Remote Caching is a powerful feature of Turborepo, but, with great power,
comes great responsibility. Make sure you are caching correctly first and
double check [handling of environment
variables](/repo/docs/crafting-your-repository/using-environment-variables).
Please also remember Turborepo treats logs as artifacts, so be aware of what
you are printing to the console.
## Vercel
[Vercel Remote Cache](https://vercel.com/docs/monorepos/remote-caching) is free to use on all plans, even if you do not host your applications on Vercel. Follow the steps below to enable Remote Caching for your repository.
### For Local Development
To link your local Turborepo to your Remote Cache, authenticate the Turborepo CLI with your Vercel account:
```bash title="Terminal"
turbo login
```
You can also use your package manager if you do not have [global `turbo`](/repo/docs/getting-started/installation#global-installation) installed:
```bash title="Terminal"
npx turbo login
```
```bash title="Terminal"
yarn dlx turbo login
```
```bash title="Terminal"
pnpm dlx turbo login
```
If your Remote Cache is configured to use single-sign-on you will need to run
`npx turbo login --sso-team=team-name` in order to get a cache token with the
correct privileges.
Now, link your Turborepo to your Remote Cache:
```bash title="Terminal"
turbo link
```
Once enabled, make some changes to a package you are currently caching and run tasks against it with `turbo run`.
Your cache artifacts will now be stored locally *and* in your Remote Cache.
To verify, delete your local Turborepo cache with:
```bash title="Terminal"
rm -rf ./.turbo/cache
```
```bash title="Terminal"
rd /s /q "./.turbo/cache"
```
Then, run the same build again. If things are working properly, `turbo` should not execute tasks locally. Instead, it will download the logs and artifacts from your Remote Cache and replay them back to you.
### Remote Caching on Vercel
If you are building and hosting your apps on Vercel, Remote Caching will be automatically set up on your behalf once you use `turbo`. Refer to the [Vercel documentation](https://vercel.com/docs/concepts/monorepos/remote-caching?utm_source=turbo.build\&utm_medium=referral\&utm_campaign=docs-link) for more information.
### Artifact Integrity and Authenticity Verification
Turborepo can sign artifacts with a secret key before uploading them to the Remote Cache. Turborepo uses `HMAC-SHA256` signatures on artifacts using a secret key you provide.
Turborepo will verify the Remote Cache artifacts' integrity and authenticity when they're downloaded.
Any artifacts that fail to verify will be ignored and treated as a cache miss by Turborepo.
To enable this feature, set the `remoteCache` options on your `turbo.json` config to include `signature: true`. Then specify your secret key by declaring the `TURBO_REMOTE_CACHE_SIGNATURE_KEY` environment variable.
```jsonc title="./turbo.json"
{
"remoteCache": {
"signature": true // [!code highlight]
}
}
```
## Remote Cache API
A Remote Cache can be implemented by any HTTP server that meets Turborepo's Remote Caching API specification.
### Managed Remote Cache with Vercel
[Vercel](https://vercel.com), the creators and maintainers of Turborepo, provide a managed Remote Cache that is fully compatible with Turborepo.
Using [Vercel Remote Cache](https://vercel.com/docs/monorepos/remote-caching) is zero-configuration and automatically integrates with [Vercel deployments](https://vercel.com/docs/deployments/overview) through the open-source [Vercel Remote Cache SDK](https://github.com/vercel/remote-cache).
Learn more about [Turborepo on Vercel](https://vercel.com/docs/monorepos/turborepo) or [deploy a template for free](https://vercel.com/templates?search=turborepo) to try it out.
### Self-hosting
You can also self-host your own Remote Cache and log into it using the `--manual` flag to provide API URL, team, and token information.
```bash title="Terminal"
turbo login --manual
```
You can [find the OpenAPI specification for the API here](/api/remote-cache-spec). At this time, all versions of `turbo` are compatible with the `v8` endpoints.
#### Community implementations
The Turborepo community has created open-source implementations of the Remote Cache.
* [`ducktors/turborepo-remote-cache`](https://github.com/ducktors/turborepo-remote-cache)
* [`Tapico/tapico-turborepo-remote-cache`](https://github.com/Tapico/tapico-turborepo-remote-cache)
file: ./content/repo-docs/crafting-your-repository/caching.mdx
meta: {
"title": "Caching",
"description": "Learn about caching in Turborepo."
}
import { Step, Steps } from '#/components/steps';
import { PackageManagerTabs, Tab } from '#/components/tabs';
import { Callout } from '#/components/callout';
Turborepo uses caching to speed up builds, ensuring you **never do the same work twice**. When your task is cacheable, Turborepo will restore the results of your task from cache using a fingerprint from the first time the task ran.

Turborepo's caching results in significant time savings when working locally - and is even more powerful when [Remote Caching](/repo/docs/core-concepts/remote-caching) is enabled, sharing a cache among your entire team and CI.
On this page, you'll learn:
* [How to hit your first Turborepo cache](#hit-your-first-turborepo-cache)
* [How to enable Remote Caching](/repo/docs/core-concepts/remote-caching)
* [What Turborepo uses for the inputs and outputs to a hash](/repo/docs/crafting-your-repository/caching#task-inputs)
* [How to troubleshoot caching issues](#troubleshooting)
Turborepo assumes that your tasks are **deterministic**. If a task is able to
produce different outputs given the set of inputs that Turborepo is aware of,
caching may not work as expected.
## Hit your first Turborepo cache
You can try out Turborepo's caching behavior in three steps:
### Create a new Turborepo project
Use `npx create-turbo@latest` and follow the prompts to create a new Turborepo.
```bash title="Terminal"
npx create-turbo@latest
```
### Run a build for the first time
If you have [`turbo` installed globally](/repo/docs/getting-started/installation#global-installation), run `turbo build` in your repository.
Alternatively, you can run the `build` script in `package.json` using your package manager.
```bash title="Terminal"
npm run build
```
```bash title="Terminal"
yarn build
```
```bash title="Terminal"
pnpm run build
```
This will result in a cache miss, since you've never ran `turbo` before with this [set of inputs](/repo/docs/crafting-your-repository/caching#task-inputs) in this repository. The inputs are turned into a hash to check for in your local filesystem cache or in [the Remote Cache](/repo/docs/core-concepts/remote-caching).
### Hit the cache
Run `turbo build` again. You will see a message like this:

Because the inputs' fingerprint is already in the cache, there's no reason to rebuild your applications from zero again. You can restore the results of the previous build from cache, saving resources and time.
## Remote Caching
Turborepo stores the results of tasks in the `.turbo/cache` directory on your machine. However, you can make your entire organization even faster by sharing this cache with your teammates and CI.
To learn more about Remote Caching and its benefits, visit the [Remote Caching page](/repo/docs/core-concepts/remote-caching).
### Enabling Remote Cache
First, authenticate with your Remote Cache provider:
```bash title="Terminal"
npx turbo login
```
Then, link the repository on your machine to Remote Cache:
```bash title="Terminal"
npx turbo link
```
Now, when you run a task, Turborepo will automatically send the outputs of the task to Remote Cache. If you run the same task on a different machine that is also authenticated to your Remote Cache, it will hit cache the first time it runs the task.
For information on how to connect your CI machines to Remote Cache, visit [the Constructing CI guide](/repo/docs/crafting-your-repository/constructing-ci#enabling-remote-caching).
By default, Turborepo uses [Vercel Remote
Cache](https://vercel.com/docs/monorepos/remote-caching) with zero
configuration. If you'd like to use a different Remote Cache, visit the
[Remote Caching API
documentation](/repo/docs/core-concepts/remote-caching#self-hosting)
## What gets cached?
Turborepo caches two types of outputs: Task outputs and Logs.
### Task outputs
Turborepo caches the file outputs of a task that are defined in [the `outputs` key](/repo/docs/reference/configuration#outputs) of `turbo.json`. When there's a cache hit, Turborepo will restore the files from the cache.
The `outputs` key is optional, see [the API reference](/repo/docs/reference/configuration#outputs) for how Turborepo behaves in this case.
If you do not declare file outputs for a task, Turborepo will not cache them. This might be okay for some tasks (like linters) - but many tasks produce files that you will want to be cached.
If you're running into errors with files not being available when you hit cache, make sure that you have defined the outputs for your task.
### Logs
Turborepo always captures the terminal outputs of your tasks, restoring those logs to your terminal from the first time that the task ran.
You can configure the verbosity of the replayed logs using [the `--output-logs` flag](/repo/docs/reference/run#--output-logs-option) or [`outputLogs` configuration option](/repo/docs/reference/configuration#outputlogs).
## Task inputs
Inputs are hashed by Turborepo, creating a "fingerprint" for the task run. When "fingerprints" match, running the task will hit the cache.
Under the hood, Turborepo creates two hashes: a global hash and a task hash. If either of the hashes change, the task will miss cache.
### Global hash inputs
| Input | Example |
| ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Resolved task definition from root `turbo.json` and package `turbo.json` | Changing [`outputs`](/repo/docs/reference/configuration#outputs) in either root `turbo.json` or [Package Configuration](/repo/docs/reference/package-configurations) |
| Lockfile changes that affect the Workspace root | Updating dependencies in root `package.json` will cause **all** tasks to miss cache |
| [`globalDependencies`](/repo/docs/reference/configuration#globaldependencies) file contents | Changing `./.env` when it is listed in `globalDependencies` will cause **all** tasks to miss cache |
| Values of variables listed in [`globalEnv`](/repo/docs/reference/configuration#globalenv) | Changing the value of `GITHUB_TOKEN` when it is listed in `globalEnv` |
| Flag values that affect task runtime | Using behavior-changing flags like `--cache-dir`, `--framework-inference`, or `--env-mode` |
| Arbitrary passthrough arguments | `turbo build -- --arg=value` will miss cache compared to `turbo build` or `turbo build -- --arg=diff` |
### Package hash inputs
| Input | Example |
| ---------------------------------------------------------------------------- | ------------------------------------------------------- |
| [Package Configuration](/repo/docs/reference/package-configurations) changes | Changing a package's `turbo.json` |
| Lockfile changes that affect the package | Updating dependencies in a package's `package.json` |
| Package's `package.json` changes | Updating the `name` field in a package's `package.json` |
| File changes in source control | Writing new code in `src/index.ts` |
## Troubleshooting
### Using dry runs
Turborepo has a [`--dry` flag](/repo/docs/reference/run#--dry----dry-run) that can be used to see what would happen if you ran a task without actually running it. This can be useful for debugging caching issues when you're not sure which tasks you're running.
For more details, visit the [`--dry` API reference](/repo/docs/reference/run#--dry----dry-run).
### Using Run Summaries
Turborepo has a [`--summarize` flag](/repo/docs/reference/run#--summarize) that can be used to get an overview of all of a task's inputs, outputs, and more. Comparing two summaries will show why two task's hashes are different. This can be useful for:
* Debugging inputs: There are many inputs to a task in Turborepo. If a task is missing cache when you expect it to hit, you can use a Run Summary to check which inputs are different that you weren't expecting.
* Debugging outputs: If cache hits aren't restoring the files you're expecting, a Run Summary can help you understand what outputs are being restored from cache.
While there is not a Turborepo-native Run Summaries UI viewer, we encourage
you to use the community-built
[https://turbo.nullvoxpopuli.com](https://turbo.nullvoxpopuli.com) if you would
like to view your Run Summaries as a web view.
### Turning off caching
Sometimes, you may not want to write the output of tasks to the cache. This can be set permanently for a task using [`"cache": false`](/repo/docs/reference/configuration#cache) or for a whole run using [ the `--no-cache` flag](/repo/docs/reference/run#--no-cache).
### Overwriting a cache
If you want to force `turbo` to re-execute a task that has been cached, use [the `--force` flag](/repo/docs/reference/run#--force). Note that this disables **reading** the cache, **not writing**.
### Caching a task is slower than executing the task
It's possible to create scenarios where caching ends up being slower than not caching. These cases are rare, but a few examples include:
* **Tasks that execute extremely fast**: If a task executes faster than a network round-trip to the [Remote Cache](/repo/docs/core-concepts/remote-caching), you should consider not caching the task.
* **Tasks whose output assets are enormous**: It's possible to create an artifact that is so big that the time to upload or download it exceeds the time to regenerate it, like a complete Docker Container. In these cases, you should consider not caching the task.
* **Scripts that have their own caching**: Some tasks have their own internal caching behavior. In these cases, configuration can quickly become complicated to make Turborepo's cache and the application cache work together.
While these situations are rare, be sure to test the behavior of your projects to determine if disabling caching in specific places provides a performance benefit.
## Next steps
Now that you've seen how Turborepo's caching makes your repository faster, let's take a look at how to develop applications and libraries in your Turborepo.
file: ./content/repo-docs/crafting-your-repository/configuring-tasks.mdx
meta: {
"title": "Configuring tasks",
"description": "Learn how to describe the workflows in your repository to get them done as fast as possible."
}
import { LinkToDocumentation } from '#/components/link-to-documentation';
import { Callout } from '#/components/callout';
import { Tabs, Tab } from '#/components/tabs';
import { Files, File, Folder } from '#/components/files';
import { ThemeAwareImage } from '#/components/theme-aware-image';
Turborepo will always run tasks in the order described in your [`turbo.json` configuration](/repo/docs/reference/configuration) and [Package Graph](/repo/docs/core-concepts/package-and-task-graph#package-graph), parallelizing work whenever possible to ensure everything runs as fast as possible. This is faster than running tasks one at a time, and it's a part of what makes Turborepo so fast.
For example, yarn workspaces run lint && yarn workspaces run test && yarn workspaces run build would look like this:
But, to get the same work done **faster** with Turborepo, you can use `turbo run lint test build`:
## Getting started
The root `turbo.json` file is where you'll register the tasks that Turborepo will run. Once you have your tasks defined, you'll be able to run one or more tasks using [`turbo run`](/repo/docs/reference/run).
* If you're starting fresh, we recommend [creating a new repository using `create-turbo`](/repo/docs/getting-started/installation) and editing the `turbo.json` file to try out the snippets in this guide.
* If you're adopting Turborepo in an existing repository, create a `turbo.json` file in the root of your repository. You'll be using it to learn about the rest of the configuration options in this guide.
## Defining tasks
Each key in the `tasks` object is a task that can be executed by `turbo run`. Turborepo will search your packages for **scripts in their `package.json` that have the same name as the task**.
To define a task, use [the `tasks` object](/repo/docs/reference/configuration#tasks) in `turbo.json`. For example, a basic task with no dependencies and no outputs named `build` might look like this:
```json title="./turbo.json"
{
"tasks": {
"build": {} // Incorrect! // [!code highlight]
}
}
```
If you run `turbo run build` at this point, Turborepo will run all `build` scripts in your packages in parallel and won't cache any file outputs. **This will quickly lead to errors.** You're missing a few important pieces to make this work how you'd expect.
### Running tasks in the right order
[The `dependsOn` key](/repo/docs/reference/configuration#dependson) is used to specify the tasks that must complete before a different task begins running. For example, in most cases, you want the `build` script for your libraries to complete before your application's `build` script runs. To do this, you'd use the following `turbo.json`:
```json title="./turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["^build"] // [!code highlight]
}
}
}
```
You now have the build order you would expect, building *dependencies* before *dependents*.
**But be careful.** At this point, you haven't marked the build outputs for caching. To do so, jump to the [Specifying outputs](#specifying-outputs) section.
#### Depending on tasks in dependencies with `^`
The `^` microsyntax tells Turborepo to run the task starting at the bottom of the dependency graph. If your application depends on a library named `ui` and the library has a `build` task, the `build` script in `ui` will run **first**. Once it has successfully completed, the `build` task in your application will run.
This is an important pattern as it ensures that your application's `build` task will have all of the necessary dependencies that it needs to compile. This concept also applies as your dependency graph grows to a more complex structure with many levels of task dependencies.
#### Depending on tasks in the same package
Sometimes, you may need to ensure that two tasks in the same package run in a specific order. For example, you may need to run a `build` task in your library before running a `test` task in the same library. To do this, specify the script in the `dependsOn` key as a plain string (without the `^`).
```json title="./turbo.json"
{
"tasks": {
"test": {
"dependsOn": ["build"] // [!code highlight]
}
}
}
```
#### Depending on a specific task in a specific package
You can also specify an individual task in a specific package to depend on. In the example below, the `build` task in `utils` must be ran before any `lint` tasks.
```json title="./turbo.json"
{
"tasks": {
"lint": {
"dependsOn": ["utils#build"] // [!code highlight]
}
}
}
```
You can also be more specific about the dependent task, limiting it to a certain package:
```json title="./turbo.json"
{
"tasks": {
"web#lint": {
"dependsOn": ["utils#build"] // [!code highlight]
}
}
}
```
With this configuration, the `lint` task in your `web` package can only be ran after the `build` task in the `utils` package is complete.
#### No dependencies
Some tasks may not have any dependencies. For example, a task for finding typos in Markdown files likely doesn't need to care about the status of your other tasks. In this case, you can omit the `dependsOn` key or provide an empty array.
```json title="./turbo.json"
{
"tasks": {
"spell-check": {
"dependsOn": [] // [!code highlight]
}
}
}
```
### Specifying `outputs`
Turborepo caches the outputs of your tasks so that you never do the same work
twice. We'll discuss this in depth in [the Caching
guide](/repo/docs/crafting-your-repository/caching), but let's make sure your
tasks are properly configured first.
The `outputs` key tells Turborepo **files and directories** it should cache when the task has successfully completed. **Without this key defined, Turborepo will not cache any files. Hitting cache on subsequent runs will not restore any file outputs.**
Below are a few examples of outputs for common tools:
```json title="./turbo.json"
{
"tasks": {
"build": {
"outputs": [".next/**", "!.next/cache/**"] // [!code highlight]
}
}
}
```
```json title="./turbo.json"
{
"tasks": {
"build": {
"outputs": ["dist/**"] // [!code highlight]
}
}
}
```
```json title="./turbo.json"
{
"tasks": {
"build": {
"outputs": ["dist/**"] // [!code highlight]
}
}
}
```
Globs are relative to the package, so `dist/**` will handle the `dist` that is outputted for each package, respectively. For more on building globbing patterns for the `outputs` key, see [the globbing specification](/repo/docs/reference/globs).
### Specifying `inputs`
The `inputs` key is used to specify the files that you want to include in the task's hash for [caching](/repo/docs/crafting-your-repository/caching). By default, Turborepo will include all files in the package that are tracked by Git. However, you can be more specific about which files are included in the hash using the `inputs` key.
As an example, a task for finding typos in Markdown files could be defined like this:
```json title="./turbo.json"
{
"tasks": {
"spell-check": {
"inputs": ["**/*.md", "**/*.mdx"] // [!code highlight]
}
}
}
```
Now, **only** changes in Markdown files will cause the `spell-check` task to miss cache.
This feature opts out of all of Turborepo's default `inputs` behavior, including following along with changes tracked by source control. This means that your `.gitignore` file will no longer be respected, and you will need to ensure that you do not capture those files with your globs.
To restore the default behavior, use [the `$TURBO_DEFAULT$` microsyntax](#restoring-defaults-with-turbo_default).
#### Restoring defaults with `$TURBO_DEFAULT$`
[The default `inputs` behavior](/repo/docs/reference/configuration#inputs) is often what you will want for your tasks. However, you can increase your cache hit ratios for certain tasks by fine-tuning your `inputs` to ignore changes to files that are known to not affect the task's output.
For this reason, you can use the `$TURBO_DEFAULT$` microsyntax to fine-tune the default `inputs` behavior:
```json title="./turbo.json"
{
"tasks": {
"build": {
"inputs": ["$TURBO_DEFAULT$", "!README.md"] // [!code highlight]
}
}
}
```
In this task definition, Turborepo will use the default `inputs` behavior for the `build` task, but will ignore changes to the `README.md` file. If the `README.md` file is changed, the task will still hit cache.
### Registering Root Tasks
You can also run scripts in the `package.json` in the Workspace root using `turbo`. For example, you may want to run a `lint:root` task for the files in your Workspace's root directory in addition to the `lint` task in each package:
```json title="./turbo.json"
{
"tasks": {
"lint": {
"dependsOn": ["^lint"]
},
"//#lint:root": {} // [!code highlight]
}
}
```
```json title="./package.json"
{
"scripts": {
"lint": "turbo run lint lint:root",
"lint:root": "eslint ." // [!code highlight]
}
}
```
With the Root Task now registered, `turbo run lint:root` will now run the task. You can also run `turbo run lint lint:root` to run all your linting tasks.
#### When to use Root Tasks
* **Linting and formatting of the Workspace root**: You might have code in your Workspace root that you want to lint and format. For example, you might want to run ESLint or Prettier in your root directory.
* **Incremental migration**: While you're migrating to Turborepo, you might have an in-between step where you have some scripts that you haven't moved to packages yet. In this case, you can create a Root Task to start migrating and fan the tasks out to packages later.
* **Scripts without a package scope**: You may have some scripts that don't make sense in the context of specific packages. Those scripts can be registered as Root Tasks so you can still run them with `turbo` for caching, parallelization, and workflow purposes.
## Advanced use cases
### Using Package Configurations
[Package Configurations](/repo/docs/reference/package-configurations) are `turbo.json` files that are placed directly into a package. This allows a package to define specific behavior for its own tasks without affecting the rest of the repository.
In large monorepos with many teams, this allows teams greater control over their own tasks. To learn more, visit [the Package Configurations documentation](/repo/docs/reference/package-configurations)
### Performing side-effects
Some tasks should always be ran no matter what, like a deployment script after a cached build. For these tasks, add `"cache": false` to your task definition.
```json title="./turbo.json"
{
"tasks": {
"deploy": {
"dependsOn": ["^build"],
"cache": false // [!code highlight]
},
"build": {
"outputs": ["dist/**"]
}
}
}
```
### Dependent tasks that can be ran in parallel
Some tasks can be ran in parallel despite being dependent on other packages. An example of tasks that fit this description are linters, since a linter doesn't need to wait for outputs in dependencies to run successfully.
Because of this, you may be tempted to define your `check-types` task like this:
```json title="./turbo.json"
{
"tasks": {
"check-types": {} // Incorrect! // [!code highlight]
}
}
```
This runs your tasks in parallel - but doesn't account for source code changes in dependencies. This means you can:
1. Make a breaking change to the interface of your `ui` package.
2. Run `turbo check-types`, hitting cache in an application package that depends on `ui`.
This is incorrect, since the application package will show a successful cache hit, despite not being updated to use the new interface. Checking for TypeScript errors in your application package manually in your editor is likely to reveal errors.
Because of this, you make a small change to your `check-types` task definition:
```json title="./turbo.json"
{
"tasks": {
"check-types": {
"dependsOn": ["^check-types"] // This works...but could be faster! // [!code highlight]
}
}
}
```
If you test out making breaking changes in your `ui` package again, you'll notice that the caching behavior is now correct. However, tasks are no longer running in parallel.
To meet both requirements (correctness and parallelism), you can introduce [Transit Nodes](/repo/docs/core-concepts/package-and-task-graph#transit-nodes) to your Task Graph:
```json title="./turbo.json"
{
"tasks": {
"transit": {
"dependsOn": ["^transit"]
},
"check-types": {
"dependsOn": ["transit"]
}
}
}
```
These Transit Nodes create a relationship between your package dependencies using a task that doesn't do anything because it doesn't match a script in any `package.json`s. Because of this, your tasks can run in parallel **and** be aware of changes to their internal dependencies.
In this example, we used the name `transit` - but you can name the task
anything that isn't already a script in your Workspace.
## Next steps
There are more options available in [the Configuring `turbo.json` documentation](/repo/docs/reference/configuration) that you will explore in the coming guides. For now, you can start running a few tasks to see how the basics work.
file: ./content/repo-docs/crafting-your-repository/constructing-ci.mdx
meta: {
"title": "Constructing CI",
"description": "Learn how Turborepo can help you efficiently complete all the necessary tasks and accelerate your development workflow."
}
import { Callout } from '#/components/callout';
import { Tabs, Tab } from '#/components/tabs';
import { Step, Steps } from '#/components/steps';
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](/repo/docs/core-concepts/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](/repo/docs/guides/ci-vendors).
## 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.
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](https://vercel.com/docs/monorepos/remote-caching#use-remote-caching-from-external-ci/cd).
For self-hosted Remote Cache options, visit [Turborepo's Remote Cache documentation](/repo/docs/core-concepts/remote-caching#remote-cache-api).
## Running tasks in CI
By [installing `turbo` globally](/repo/docs/getting-started/installation#global-installation) 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](/repo/docs/crafting-your-repository/configuring-tasks) page.
* For examples of running tasks in CI, visit our [CI guides](/repo/docs/guides/ci-vendors).
### Filtering for entry points
You can filter your tasks using [the `--filter` flag](/repo/docs/reference/run#--filter-string) exactly the same as when you're working with `turbo` locally. Filtering by packages, directories, and Git history are all supported 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](#running-only-affected-tasks) to only run tasks in packages that have changes.
## Docker
Docker is an important part of many deployment pipelines. [Turborepo's `prune` subcommand](/repo/docs/reference/prune) 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](/repo/docs/guides/tools/docker).
## Skipping tasks and other unnecessary work
### Running only affected tasks
You can use the `--affected` flag to only run tasks that have changes.
```bash title="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](/repo/docs/reference/run#advanced-filtering-examples) or [`turbo-ignore`](/repo/docs/reference/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 tasks only for the packages 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.
By default, `turbo-ignore` uses the parent commit. To customize for more
depth, see [the turbo-ignore reference](/repo/docs/reference/turbo-ignore).
### 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:
```bash title="Terminal"
npx turbo-ignore web
```
Check for changes for the `build` task for the `web` package and its dependencies using [Automatic Package Scoping](/repo/docs/crafting-your-repository/running-tasks#automatic-package-scoping):
```bash title="Terminal"
cd apps/web
npx turbo-ignore
```
Check for changes for the `test` task for the `docs` package and its dependencies using [Automatic Package Scoping](/repo/docs/crafting-your-repository/running-tasks#automatic-package-scoping) and the `--task` flag:
```bash title="Terminal"
cd apps/docs
npx turbo-ignore --task=test
```
### Handle the result
If changes are detected in the package or its [Internal Dependencies](/repo/docs/core-concepts/internal-packages), `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](/repo/docs/reference/turbo-ignore).
## Best practices
### Rely on caching
Turborepo's caching abilities allow you to create fast CI pipelines with minimal complexity. Through [Remote Caching](/repo/docs/core-concepts/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](/repo/docs/crafting-your-repository/running-tasks#automatic-package-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](/repo/docs/guides/tools/docker#example). 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`](/repo/docs/reference/prune) and [`turbo generate`](/repo/docs/reference/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](/repo/docs/reference/configuration#outputs) 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](/repo/docs/guides) or [dive deeper into core concepts](/repo/docs/core-concepts).
file: ./content/repo-docs/crafting-your-repository/creating-an-internal-package.mdx
meta: {
"title": "Creating an Internal Package",
"description": "Learn how to create an Internal Package for your monorepo."
}
import { Callout } from '#/components/callout';
import { Steps, Step } from '#/components/steps';
import { PackageManagerTabs, Tabs, Tab } from '#/components/tabs';
import { Files, File, Folder } from '#/components/files';
[Internal Packages](/repo/docs/core-concepts/internal-packages) are the building blocks of your workspace, giving you a powerful way to share code and functionality across your repo. Turborepo automatically understands the relationships between Internal Packages using the dependencies in `package.json`, creating a [Package Graph](/repo/docs/core-concepts/package-and-task-graph#package-graph) under the hood to optimize your repository's workflows.

Let's create your first Internal Package to share math utilities in your repo using the guidance in the [Anatomy of a package](/repo/docs/crafting-your-repository/structuring-a-repository#anatomy-of-a-package) section and the [Compiled Packages](/repo/docs/core-concepts/internal-packages#compiled-packages) pattern. In the steps below, we assume you've [created a new repository using `create-turbo`](/repo/docs/getting-started/installation) or are using a similarly structured repository.
### Create an empty directory
You'll need a directory to put the package in. Let's create one at `./packages/math`.
### Add a package.json
Next, create the `package.json` for the package. By adding this file, you'll fulfill [the two requirements for an Internal Package](/repo/docs/crafting-your-repository/structuring-a-repository#specifying-packages-in-a-monorepo), making it discoverable to Turborepo and the rest of your Workspace:
```json title="./packages/math/package.json"
{
"name": "@repo/math",
"type": "module",
"scripts": {
"dev": "tsc --watch",
"build": "tsc"
},
"exports": {
"./add": {
"types": "./src/add.ts",
"default": "./dist/add.js"
},
"./subtract": {
"types": "./src/subtract.ts",
"default": "./dist/subtract.js"
}
},
"devDependencies": {
"@repo/typescript-config": "*",
"typescript": "latest"
}
}
```
```json title="./packages/math/package.json"
{
"name": "@repo/math",
"type": "module",
"scripts": {
"dev": "tsc --watch",
"build": "tsc"
},
"exports": {
"./add": {
"types": "./src/add.ts",
"default": "./dist/add.js"
},
"./subtract": {
"types": "./src/subtract.ts",
"default": "./dist/subtract.js"
}
},
"devDependencies": {
"@repo/typescript-config": "workspace:*",
"typescript": "latest"
}
}
```
```json title="./packages/math/package.json"
{
"name": "@repo/math",
"type": "module",
"scripts": {
"dev": "tsc --watch",
"build": "tsc"
},
"exports": {
"./add": {
"types": "./src/add.ts",
"default": "./dist/add.js"
},
"./subtract": {
"types": "./src/subtract.ts",
"default": "./dist/subtract.js"
}
},
"devDependencies": {
"@repo/typescript-config": "workspace:*",
"typescript": "latest"
}
}
```
Let's break down this `package.json` piece-by-piece:
* **`scripts`**: The `dev` and `build` script compile the package using [the TypeScript compiler](https://www.typescriptlang.org/docs/handbook/compiler-options.html). The `dev` script will watch for changes to source code and automatically recompile the package.
* **`devDependencies`**: `typescript` and `@repo/typescript-config` are `devDependencies` so you can use those packages in the `@repo/math` package. In a real-world package, you will likely have more `devDependencies` and `dependencies` - but we can keep it simple for now.
* **`exports`**: Defines multiple entrypoints for the package so it can be used in other packages (`import { add } from '@repo/math'`).
Notably, this `package.json` declares an Internal Package, `@repo/typescript-config`, as a dependency. Turborepo will recognize `@repo/math` as a dependent of `@repo/typescript-config` for ordering your tasks.
### Add a `tsconfig.json`
Specify the TypeScript configuration for this package by adding a `tsconfig.json` file to **the root of the package**. TypeScript has [an `extends` key](https://www.typescriptlang.org/tsconfig#extends), allowing you to use a base configuration throughout your repository and overwrite with different options as needed.
```json title="./packages/math/tsconfig.json"
{
"extends": "@repo/typescript-config/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
```
You've done four important things here:
* The `@repo/typescript-config/base.json` configuration that lives in `./packages/typescript-config` has all the configuration you need so you extend from it.
* [The `outDir` key](https://www.typescriptlang.org/tsconfig/#outDir) in `compilerOptions` tells TypeScript where to put the compiled output. It matches the directory specified in your `exports` in `package.json`.
* [The `rootDir` key in `compilerOptions`](https://www.typescriptlang.org/tsconfig/#rootDir) ensures that the output in `outDir` uses the same structure as the `src` directory.
* The [`include`](https://www.typescriptlang.org/tsconfig/#include) and [`exclude`](https://www.typescriptlang.org/tsconfig/#exclude) keys are not inherited from the base configuration, [according to the TypeScript specification](https://www.typescriptlang.org/tsconfig#include), so you've included them here.
There's a lot more to learn about TypeScript configuration, but this is a good
place to start for now. If you'd like to learn more, visit [the official
TypeScript documentation](https://www.typescriptlang.org/tsconfig) or [our
TypeScript guide](/repo/docs/guides/tools/typescript).
### Add a `src` directory with source code
You can now write some code for your package. Create two files inside a `src` directory:
```ts title="./packages/math/src/add.ts"
export const add = (a: number, b: number) => a + b;
```
```ts title="./packages/math/src/subtract.ts"
export const subtract = (a: number, b: number) => a - b;
```
These files map to the outputs that will be created by `tsc` when you run `turbo build` in a moment.
### Add the package to an application
You're ready to use your new package in an application. Let's add it to the `web` application.
```diff title="apps/web/package.json"
"dependencies": {
+ "@repo/math": "*",
"next": "latest",
"react": "latest",
"react-dom": "latest"
},
```
```diff title="apps/web/package.json"
"dependencies": {
+ "@repo/math": "*",
"next": "latest",
"react": "latest",
"react-dom": "latest"
},
```
```diff title="apps/web/package.json"
"dependencies": {
+ "@repo/math": "workspace:*",
"next": "latest",
"react": "latest",
"react-dom": "latest"
},
```
You just changed the dependencies in your repo. Make sure to run your package
manager's installation command to update your lockfile.
`@repo/math` is now available in the `web` application, you can use it in your code:
```tsx title="apps/web/src/app/page.tsx"
import { add } from '@repo/math/add';
function Page() {
return
{add(1, 2)}
;
}
export default Page;
```
### Edit `turbo.json`
Add the artifacts for the new `@repo/math` library to the `outputs` for the `build` task in `turbo.json`. This ensures that its build outputs will be cached by Turborepo, so they can be restored instantly when you start running builds.
```json title="./turbo.json"
// [!code word:"dist/**"]
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
}
}
}
```
### Run `turbo build`
If you've [installed `turbo` globally](/repo/docs/getting-started/installation#global-installation), run `turbo build` in your terminal at the root of your Workspace. You can also run the `build` script from `package.json` with your package manager, which will use `turbo run build`.
The `@repo/math` package built before the `web` application built so that the runtime code in `./packages/math/dist` is available to the `web` application when it bundles.
You can run `turbo build` again to see your `web` application rebuild in
**milliseconds**. We'll discuss this at length in [the Caching
guide](/repo/docs/crafting-your-repository/caching).
## Best practices for Internal Packages
### One "purpose" per package
When you're creating Internal Packages, it's recommended to create packages that have a single "purpose". This isn't a strict science or rule, but a best practice depending on your repository, your scale, your organization, what your teams need, and more. This strategy has several advantages:
* **Easier to understand**: As a repository scales, developers working in the repository will more easily be able to find the code they need.
* **Reducing dependencies per package**: Using fewer dependencies per package makes it so Turborepo can more effectively [prune the dependencies of your package graph](/repo/docs/reference/prune).
Some examples include:
* **`@repo/ui`**: A package containing all of your shared UI components
* **`@repo/tool-specific-config`**: A package for managing configuration of a specific tool
* **`@repo/graphs`**: A domain-specific library for creating and manipulating graphical data
### Application Packages do not contain shared code
When you're creating [Application Packages](/repo/docs/core-concepts/package-types#application-packages), it's best to avoid putting shared code in those packages. Instead, you should create a separate package for the shared code and have the application packages depend on that package.
Additionally, Application Packages are not meant to be installed into other packages. Instead, they should be thought of as an entrypoint to your [Package Graph](/repo/docs/core-concepts/package-and-task-graph#package-graph).
There are [rare
exceptions](/repo/docs/core-concepts/package-types#installing-an-applicaiton-package-into-another-package)
to this rule.
## Next steps
With a new Internal Package in place, you can start [configuring tasks](/repo/docs/crafting-your-repository/configuring-tasks).
file: ./content/repo-docs/crafting-your-repository/developing-applications.mdx
meta: {
"title": "Developing applications",
"description": "Learn how to develop applications in your repository."
}
import { Tabs, Tab } from '#/components/tabs';
import { LinkToDocumentation } from '#/components/link-to-documentation';
Developing applications in a monorepo unlocks powerful workflows, enabling you to make atomic commits to source control with easy access to code.
Most development tasks are long-running tasks that watch for changes to your code. Turborepo enhances this experience with a powerful terminal UI and other capabilities like:
* [Configuration for `dev` tasks](#configuring-development-tasks)
* [Interacting with tasks](#interacting-with-tasks)
* [Watch Mode](#watch-mode)
* [Running setup scripts](#running-setup-tasks-before-dev)
* [Filtering tasks to run a subset of your packages](#running-a-specific-application)
## Configuring development tasks
Defining a development task in `turbo.json` tells Turborepo that you'll be running a long-lived task. This is useful for things like running a development server, running tests, or building your application.
To register a `dev` task, add it to your `turbo.json` with two properties:
```json title="./turbo.json"
{
"tasks": {
"dev": {
"cache": false,
"persistent": true
}
}
}
```
* **"cache": false**: Tells Turborepo to not attempt to cache the results of the task. Since this is a development task, you're likely to be making frequent changes to your code, so caching the results is not useful.
* **"persistent": true**: Tells Turborepo to keep the task running until you stop it. This key serves as a signal for your terminal UI to treat the task as long-running and interactive. Additionally, it prevents you from accidentally depending on a task that will not exit.
You can now run your `dev` task to start your development scripts in parallel:
```bash title="Terminal"
turbo dev
```
### Running setup tasks before `dev`
You may also want to run scripts that set up your development environment or pre-build packages. You can make sure those tasks run before the `dev` task with `dependsOn`:
```json title="./turbo.json"
{
"tasks": {
"dev": {
"cache": false,
"persistent": true,
"dependsOn": ["//#dev:setup"]
},
"//#dev:setup": {
"outputs": [".codegen/**"]
}
}
}
```
In this example, we're using a [Root Task](/repo/docs/crafting-your-repository/configuring-tasks#registering-root-tasks) but you can use the same idea for [arbitrary tasks in packages](/repo/docs/crafting-your-repository/configuring-tasks#depending-on-a-specific-task-in-a-specific-package).
### Running a specific application
The `--filter` flag allows you to pick a subset of your [Package Graph](/repo/docs/core-concepts/package-and-task-graph#package-graph) so you can run your `dev` task for a specific application and its dependencies:
```bash title="Terminal"
turbo dev --filter=web
```
## Using the terminal UI
Turborepo's terminal UI enables a number of features that create a highly interactive experience around your tasks.
### Customizing your view
You can quickly adjust the UI to your needs using keybinds.
| Keybind | Action |
| ------- | ----------------------------------------------------------------- |
| `m` | Toggle popup listing keybinds |
| `↑`/`↓` | Select the next/previous task in the task list |
| `j`/`k` | Select the next/previous task in the task list |
| `p` | Toggle selection pinning for selected task |
| `h` | Toggle visibility of the task list |
| `c` | When logs are highlighted, copy selection to the system clipboard |
| `u`/`d` | Scroll logs `u`p and `d`own |
### Interacting with tasks
Some of your tools may allow you to type input into them. Examples of this include Drizzle ORM's interactive migrations or Jest's filtering and re-running of test suites.
You can interact with tasks that are [marked as interactive](/repo/docs/reference/configuration#interactive) to give them input.
| Keybind | Action |
| -------- | ----------------- |
| `i` | Begin interacting |
| `Ctrl+z` | Stop interacting |
## Watch Mode
Many tools have a built-in watcher, like [`tsc --watch`](https://www.typescriptlang.org/docs/handbook/compiler-options.html#compiler-options),
that will respond to changes in your source code. However, some don't.
`turbo watch` adds a dependency-aware watcher to any tool. Changes to source code will follow [the Task Graph](/repo/docs/core-concepts/package-and-task-graph#task-graph) that you've described in `turbo.json`, just like all your other tasks.
For example, using a package structure like [`create-turbo`](/repo/docs/reference/create-turbo) with the following tasks and scripts:
```json title="turbo.json"
{
"tasks": {
"dev": {
"persistent": true,
"cache": false
},
"lint": {
"dependsOn": ["^lint"]
}
}
}
```
```json title="turbo.json"
{
"name": "@repo/ui"
"scripts": {
"dev": "tsc --watch",
"lint": "eslint ."
}
}
```
```json title="turbo.json"
{
"name": "web"
"scripts": {
"dev": "next dev",
"lint": "eslint ."
},
"dependencies": {
"@repo/ui": "workspace:*"
}
}
```
When you run `turbo watch dev lint`, you'll see the `lint` scripts are re-run whenever you make source code changes, despite ESLint not having a built-in watcher. `turbo watch` is also aware of internal dependencies, so a code change in `@repo/ui` will re-run the task in both `@repo/ui` and `web`.
The Next.js development server in `web` and the TypeScript Compiler's built-in watcher in `@repo/ui` will continue to work as usual, since they are marked with `persistent`.
For more information, [visit the `turbo watch` reference](/repo/docs/reference/watch).
## Limitations
### Teardown tasks
In some cases, you may want to run a script when the `dev` task is stopped. Turborepo is unable to run those teardown scripts when exiting because `turbo` exits when your `dev` tasks exit.
Instead, create a `turbo dev:teardown` script that you run separately after you've exited your primary `turbo dev` task.
## Next steps
Once you have a version of your application that you'd like to deploy, it's time to learn how to configure environment variables in Turborepo.
file: ./content/repo-docs/crafting-your-repository/index.mdx
meta: {
"title": "Crafting your repository",
"description": "Design and build your Turborepo."
}
import { Card, Cards } from '#/components/card';
import { Callout } from '#/components/callout';
Architecting a monorepo is a careful process. Through these guides, you'll learn how to design and build a monorepo that will make every team faster - no matter the size.
The guides in this section will take you through building a multi-package workspace, commonly referred to as a monorepo. They are meant to be read in order as they build on top of the knowledge from previous guides, but you can read them in any order or skip to the pages specific to your use case.
By the time you've read through all of this section, you should have a good understanding of how to design and build a monorepo with Turborepo.
Turborepo can also be used to speed up single-package workspaces. Visit the
[single-package workspace](/repo/docs/guides/single-package-workspaces)
section for more information.
## From zero to `turbo`
## More guides
We also have more guides centered around [specific tools, use cases, and other topics](/repo/docs/guides).
file: ./content/repo-docs/crafting-your-repository/managing-dependencies.mdx
meta: {
"title": "Managing dependencies",
"description": "Learn how to manage dependencies in your monorepo's workspace."
}
import { PackageManagerTabs, Tab } from '#/components/tabs';
import { Callout } from '#/components/callout';
import { LinkToDocumentation } from '#/components/link-to-documentation';
* **External dependencies** come from [the npm registry](https://www.npmjs.com/), allowing you to leverage valuable code from the ecosystem to build your applications and libraries faster.
* **Internal dependencies** let you share functionality within your repository, dramatically improving discoverability and usability of shared code. We will discuss how to build an Internal Package in [the next guide](/repo/docs/crafting-your-repository/creating-an-internal-package).
```json title="./apps/web/package.json"
{
"dependencies": {
"next": "latest", // External dependency
"@repo/ui": "*" // Internal dependency
}
}
```
```json title="./apps/web/package.json"
{
"dependencies": {
"next": "latest", // External dependency
"@repo/ui": "*" // Internal dependency
}
}
```
```json title="./apps/web/package.json"
{
"dependencies": {
"next": "latest", // External dependency
"@repo/ui": "workspace:*" // Internal dependency
}
}
```
## Best practices for dependency installation
### Install dependencies where they're used
When you install a dependency in your repository, you should install it directly in the package that uses it. The package's `package.json` will have every dependency that the package needs. This is true for both external and internal dependencies.
Note that your package manager may choose to [use a different node\_modules
location than the package](#node_modules-locations).
To quickly install dependencies in multiple packages, you can use your package manager:
```bash title="Terminal"
npm install jest --workspace=web --workspace=@repo/ui --save-dev
```
npm documentation
Yarn 1:
```bash title="Terminal"
yarn workspace web add jest --dev
yarn workspace @repo/ui add jest --dev
```
Yarn 1 documentation
Yarn 2+:
```bash title="Terminal"
yarn workspaces foreach -R --from '{web,@repo/ui}' add jest --dev
```
Yarn 2+ documentation
```bash title="Terminal"
pnpm install jest --save-dev --recursive --filter=web --filter=@repo/ui --filter=@repo/web
```
pnpm documentation
This practice has several benefits:
* **Improved clarity**: It's easier to understand what a package depends on when its dependencies are listed in its `package.json`. Developers working in the repository can see at a glance what dependencies are used within the package.
* **Enhanced flexibility**: In a monorepo at scale, it can be unrealistic to expect each package to use the same version of an external dependency. When there are many teams working in the same codebase, there will be differing priorities, timelines, and needs due to the realities of [operating at scale](https://vercel.com/blog/how-to-scale-a-large-codebase). By installing dependencies in the package that uses them, you can enable your `ui` team to bump to the latest version of TypeScript, while your `web` team can prioritize shipping new features and bumping TypeScript later. Additionally, if you still want to keep dependency versions in sync, [you can do that, too](/repo/docs/crafting-your-repository/managing-dependencies#keeping-dependencies-on-the-same-version).
* **Better caching ability**: If you install too many dependencies in the root of your repository, you'll be changing the workspace root whenever you add, update, or delete a dependency, leading to unnecessary cache misses.
* **Pruning unused dependencies**: For Docker users, [Turborepo's pruning feature](/repo/docs/reference/prune) can remove unused dependencies from Docker images to create lighter images. When dependencies are installed in the packages that they are meant for, Turborepo can read your lockfile and remove dependencies that aren't used in the packages you need.
### Few dependencies in the root
Following the first principle above to [install dependencies in the package where they're used](#install-dependencies-where-theyre-used), you'll find that you naturally end up with few dependencies in the root of your workspace.
The only dependencies that belong in the workspace root are **tools for managing the repository** whereas dependencies for building applications and libraries are installed in their respective packages. Some examples of dependencies that make sense to install in the root are [`turbo`](https://www.npmjs.com/package/turbo), [`husky`](https://www.npmjs.com/package/husky), or [`lint-staged`](https://www.npmjs.com/package/lint-staged).
## Managing dependencies
### Turborepo does not manage dependencies
Note that Turborepo does not play a role in managing your dependencies, leaving that work up to your package manager of choice.
It's up to the package manager to handle things like downloading the right external dependency version, symlinking, and resolving modules. The recommendations on this page are best practices for managing dependencies in a Workspace, and are not enforced by Turborepo.
### Module resolution differs amongst package managers
Package managers have different module resolution algorithms, which leads to differences in behavior that can be difficult to predict.
In the Turborepo documentation, we make many recommendations according to the expected behaviors of the package managers. Our coverage of how to handle dependencies is best effort and you may need to adapt the documented behavior for your package manager or repository's needs.
However, if you find an issue with the documentation that appears to be universally incorrect for all package managers or a specific one, please let us know with a GitHub Issue so we can improve.
### node\_modules locations
Depending on your choice of package manager, version, settings, and where your dependencies are installed in your Workspace, you may see `node_modules` and the dependencies inside it in various locations within the Workspace. Dependencies could be found in the root `node_modules`, in packages' `node_modules`, or both.
As long as your scripts and tasks are able to find the dependencies they need, your package manager is working correctly.
The specific locations for `node_modules` within the Workspace are not a part of the public API of package managers. This means that referencing `node_modules` directly (like `node ./node_modules/a-package/dist/index.js`) can be brittle, since the location of the dependency on disk can change with other dependency changes around the Workspace.
Instead, rely on conventions of the Node.js ecosystem for accessing dependency modules whenever possible.
### Keeping dependencies on the same version
Some monorepo maintainers prefer to keep dependencies on the same version across all packages by rule. There are several ways to achieve this:
#### Using purpose-built tooling
Tools like [`syncpack`](https://www.npmjs.com/package/syncpack), [`manypkg`](https://www.npmjs.com/package/@manypkg/cli), and [`sherif`](https://www.npmjs.com/package/sherif) can be used for this specific purpose.
#### Using your package manager
You can use your package manager to update dependency versions in one command.
```bash title="Terminal"
npm install typescript@latest --workspaces
```
[→ npm documentation](https://docs.npmjs.com/cli/v7/using-npm/config#workspaces)
Yarn 1:
```bash title="Terminal"
yarn upgrade-interactive --latest
```
[→ Yarn 1 documentation](https://classic.yarnpkg.com/en/docs/cli/upgrade-interactive)
Yarn 2+:
```bash title="Terminal"
yarn upgrade typescript@latest --upgrade
```
[→ Yarn 2+ documentation](https://yarnpkg.com/cli/up)
```bash title="Terminal"
pnpm up --recursive typescript@latest
```
[→ pnpm documentation](https://pnpm.io/cli/update#--recursive--r)
#### Using an IDE
Your IDE's refactoring tooling can find and replace the version of a dependency across all `package.json` files in your repository at once. Try using a regex like `"next": ".*"` on `package.json` files to find all instances of the `next` package and replace them with the version you want. When you're done, make sure to run your package manager's install command to update your lockfile.
## Next steps
Now that you know how to manage dependencies effectively in a workspace, let's [create an Internal Package](/repo/docs/crafting-your-repository/creating-an-internal-package) to be used as a dependency in your monorepo.
file: ./content/repo-docs/crafting-your-repository/running-tasks.mdx
meta: {
"title": "Running tasks",
"description": "Learn how to run tasks in your repository through the `turbo` CLI."
}
import { Callout } from '#/components/callout';
import { PackageManagerTabs, Tab } from '#/components/tabs';
import { LinkToDocumentation } from '#/components/link-to-documentation';
import { InVersion } from '#/components/in-version';
Turborepo optimizes the developer workflows in your repository by automatically parallelizing and caching tasks. Once a task is [registered in `turbo.json`](/repo/docs/crafting-your-repository/configuring-tasks), you have a powerful new toolset for running the scripts in your repository:
* [Use `scripts` in `package.json` for tasks you need to run often](#using-scripts-in-packagejson)
* [Use global `turbo` to quickly run custom tasks on-demand](#using-global-turbo)
* [Filter tasks by directories, package names, source control changes, and more](#using-filters)
Running tasks through `turbo` is powerful because you get one model for executing workflows throughout your repository in development and in your CI pipelines.
## Using `scripts` in `package.json`
For tasks that you run frequently, you can write your `turbo` commands directly into your root `package.json`.
```jsonc title="./package.json"
{
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build",
"test": "turbo run test",
"lint": "turbo run lint"
}
}
```
`turbo` is an alias for `turbo run` - but we recommend using `turbo run` in
`package.json` and CI workflows to avoid potential collisions with possible
`turbo` subcommands that could be added in the future.
These scripts can then be run using your package manager.
```bash title="Terminal"
npm run dev
```
```bash title="Terminal"
yarn dev
```
```bash title="Terminal"
pnpm dev
```
You only want to write `turbo` commands in your root `package.json`. Writing `turbo` commands into the `package.json` of packages can lead to recursively
calling `turbo`.
## Using global `turbo`
[Installing `turbo` globally](/repo/docs/getting-started/installation#global-installation) lets you run commands directly from your terminal. This improves your local development experience since it makes it easier to run exactly what you need, when you need it.
Additionally, global `turbo` is useful in your CI pipelines, giving you maximum control of exactly which tasks to run at each point in your pipeline.
### Automatic Package Scoping
When you're in a package's directory, `turbo` will automatically scope commands to the [Package Graph](/repo/docs/core-concepts/package-and-task-graph#package-graph) for that package. This means you can quickly write commands without having to [write filters](/repo/docs/reference/run#--filter-string) for the package.
```bash title="Terminal"
cd apps/docs
turbo build
```
In the example above, the `turbo build` command will run the `build` task for the `docs` package using the `build` task registered in `turbo.json`.
[Using a filter](#using-filters) will override Automatic Package Scoping.
### Customizing behavior
In [the documentation for the `run` subcommand](/repo/docs/reference/run), you'll find many useful flags to tailor the behavior of `turbo run` for what you need. When running global `turbo`, you can go faster using workflows like:
* **Variations of your most common commands**: The `build` script in `package.json` has the most utility when it is `turbo build` - but you might only be interested in a specific package at the moment. You can quickly filter for the specific package you're interested in using `turbo build --filter=@repo/ui`.
* **One-off commands**: Commands like `turbo build --dry` aren't needed often so you likely won't create a script in your `package.json` for it. Instead, you can run it directly in your terminal whenever you need it.
* **Overriding `turbo.json` configuration**: Some CLI flags have an equivalent in `turbo.json` that you can override. For instance, you may have a `turbo build` command configured to use [`"outputLogs": "full"` in `turbo.json`](/repo/docs/reference/configuration#outputlogs) - but you're only interested in seeing errors at the moment. Using global `turbo`, you can use `turbo lint --output-logs=errors-only` to only show errors.
## Running multiple tasks
`turbo` is able to run multiple tasks, parallelizing whenever possible.
```bash title="Terminal"
turbo run build test lint check-types
```
This command will run all of the tasks, automatically detecting where it can run a script as early as possible, according to your task definitions.
`turbo test lint` will run tasks exactly the same as `turbo lint test`.
If you want to ensure that one task blocks the execution of another, express that relationship in your [task configurations](/repo/docs/crafting-your-repository/configuring-tasks#defining-tasks).
## Using filters
While [caching](/repo/docs/crafting-your-repository/running-tasks) ensures you stay fast by never doing the same work twice, you can also filter tasks to run only a subset of [the Task Graph](/repo/docs/core-concepts/package-and-task-graph#task-graph).
There are many advanced use cases for filtering in [the `--filter` API reference](/repo/docs/reference/run#--filter-string) but the most common use cases are discussed below.
### Filtering by package
Filtering by package is a simple way to only run tasks for the packages you're currently working on.
```bash title="Terminal"
turbo build --filter=@acme/web
```
You can also filter to a specific task for the package directly in your CLI command without needing to use `--filter`:
```bash title="Terminal"
# Run the `build` task for the `web` package
turbo run web#build
# Run the `build` task for the `web` package, and the `lint` task for the `docs` package
turbo run web#build docs#lint
```
### Filtering by directory
Your repository might have a directory structure where related packages are grouped together. In this case, you can capture the glob for that directory to focus `turbo` on those packages.
```bash title="Terminal"
turbo lint --filter="./packages/utilities/*"
```
### Filtering to include dependents
When you're working on a specific package, you might want to run tasks for the package and its dependents. The `...` microsyntax is useful when you're making changes to a package and want to ensure that the changes don't break any of its dependents.
```bash title="Terminal"
turbo build --filter=...ui
```
### Filtering to include dependencies
To limit the scope to a package and its dependencies, append `...` to the package name. This runs the task for the specified package and all packages it depends on.
```bash title="Terminal"
turbo dev --filter=web...
```
### Filtering by source control changes
Using filters to run tasks based on changes in source control is a great way to run tasks only for the packages that are affected by your changes. **Source control filters must be wrapped in `[]`**.
* **Comparing to the previous commit**: `turbo build --filter=[HEAD^1]`
* **Comparing to the main branch**: `turbo build --filter=[main...my-feature]`
* **Comparing specific commits using SHAs**: `turbo build --filter=[a1b2c3d...e4f5g6h]`
* **Comparing specific commits using branch names**: `turbo build --filter=[your-feature...my-feature]`
In general, you can rely on caching to keep your repository fast. When you're
using [Remote Caching](/repo/docs/core-concepts/remote-caching), you can count
on hitting cache for unchanged packages.
### Combining filters
For even more specificity, you can combine filters to further refine the entrypoints into your [Task Graph](/repo/docs/core-concepts/package-and-task-graph#task-graph).
```bash title="Terminal"
turbo build --filter=...ui --filter={./packages/*} --filter=[HEAD^1]
```
Multiple filters are combined as a **union**, meaning that the [Task Graph](/repo/docs/core-concepts/package-and-task-graph#task-graph) will include tasks that match any of the filters. For more information on advanced usage of filters, see [the `--filter` API reference](/repo/docs/reference/run#--filter-string).
## Next steps
When you start running tasks in your repository, you might start noticing that your tasks get faster. Next, you'll explore [caching](/repo/docs/crafting-your-repository/caching) and how `turbo` makes it so you never do the same work twice.
file: ./content/repo-docs/crafting-your-repository/structuring-a-repository.mdx
meta: {
"title": "Structuring a repository",
"description": "Start by creating a repository using the conventions of the ecosystem."
}
import { Callout } from '#/components/callout';
import { PackageManagerTabs, Tab, Tabs } from '#/components/tabs';
import { Step, Steps } from '#/components/steps';
import { File, Folder, Files } from '#/components/files';
import { LinkToDocumentation } from '#/components/link-to-documentation';
`turbo` is built on top of [Workspaces](https://vercel.com/docs/vercel-platform/glossary#workspace), a feature of package managers in the JavaScript ecosystem that allows you to group multiple packages in one repository.
Following these conventions is important because it allows you to:
* Lean on those conventions for all your repo's tooling
* Quickly, incrementally adopt Turborepo into an existing repository
In this guide, we'll walk through setting up a multi-package workspace (monorepo) so we can set the groundwork for `turbo`.
## Getting started
Setting up a workspace's structure can be tedious to do by hand. If you're new to monorepos, we recommend [using `create-turbo` to get started](/repo/docs/getting-started/installation) with a valid workspace structure right away.
```bash title="Terminal"
npx create-turbo@latest
```
You can then review the repository for the characteristics described in this guide.
## Anatomy of a workspace
In JavaScript, a workspace can either be [a single package](/repo/docs/guides/single-package-workspaces) or a collection of packages. In these guides, we'll be focusing on [a multi-package workspace](https://vercel.com/docs/vercel-platform/glossary#monorepo), often called a "monorepo".
Below, the structural elements of `create-turbo` that make it a valid workspace are highlighted.
### Minimum requirements
* [Packages as described by your package manager](#specifying-packages-in-a-monorepo)
* [A package manager lockfile](#package-manager-lockfile)
* [Root `package.json`](#root-packagejson)
* [Root `turbo.json`](#root-turbojson)
* [`package.json` in each package](#packagejson-in-each-package)
### Specifying packages in a monorepo
#### Declaring directories for packages
First, your package manager needs to describe the locations of your packages. We recommend starting with splitting your packages into `apps/` for applications and services and `packages/` for everything else, like libraries and tooling.
```json title="./package.json"
{
"workspaces": [
"apps/*",
"packages/*"
]
}
```
npm workspace documentation
```json title="./package.json"
{
"workspaces": [
"apps/*",
"packages/*"
]
}
```
yarn workspace documentation
```json title="pnpm-workspace.yaml"
packages:
- "apps/*"
- "packages/*"
```
pnpm workspace documentation
Using this configuration, every directory **with a `package.json`** in the `apps` or `packages` directories will be considered a package.
Turborepo does not support nested packages like `apps/**` or `packages/**` due to ambiguous behavior among package managers in the JavaScript ecosystem. Using a structure that would put a package at `apps/a` and another at `apps/a/b` will result in an error.
If you'd like to group packages by directory, you can do this using globs like `packages/*` and `packages/group/*` and **not** creating a `packages/group/package.json` file.
#### `package.json` in each package
In the directory of the package, there must be a `package.json` to make the package discoverable to your package manager and `turbo`. The [requirements for the `package.json` of a package](#anatomy-of-a-package) are below.
### Root `package.json`
The root `package.json` is the base for your workspace. Below is a common example of what you would find in a root `package.json`:
```json title="./package.json"
{
"private": true,
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint"
},
"devDependencies": {
"turbo": "latest"
},
"packageManager": "npm@10.0.0"
}
```
```json title="./package.json"
{
"private": true,
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint"
},
"devDependencies": {
"turbo": "latest"
},
"packageManager": "yarn@1.22.19"
}
```
```json title="./package.json"
{
"private": true,
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint"
},
"devDependencies": {
"turbo": "latest"
},
"packageManager": "pnpm@9.0.0"
}
```
### Root `turbo.json`
`turbo.json` is used to configure the behavior of `turbo`. To learn more about how to configure your tasks, visit the [Configuring tasks](/repo/docs/crafting-your-repository/configuring-tasks) page.
### Package manager lockfile
A lockfile is key to reproducible behavior for both your package manager and `turbo`. Additionally, Turborepo uses the lockfile to understand the dependencies between your [Internal Packages](/repo/docs/core-concepts/internal-packages) within your Workspace.
If you do not have a lockfile present when you run `turbo`, you may see
unpredictable behavior.
## Anatomy of a package
It's often best to start thinking about designing a package as its own unit within the Workspace. At a high-level, each package is almost like its own small "project", with its own `package.json`, tooling configuration, and source code. There are limits to this idea—but its a good mental model to *start* from.
Additionally, a package has specific entrypoints that other packages in your Workspace can use to access the package, specified by [`exports`](#exports).
### `package.json` for a package
#### `name`
[The `name` field](https://nodejs.org/api/packages.html#name) is used to identify the package. It should be unique within your workspace.
It's best practice to use a namespace prefix for your [Internal Packages](/repo/docs/core-concepts/internal-packages) to avoid conflicts with other packages on the npm registry. For example, if your organization is named `acme`, you might name your packages `@acme/package-name`.
We use `@repo` in our docs and examples because it is an unused, unclaimable namespace on the npm registry. You can choose to keep it or use your own prefix.
#### `scripts`
The `scripts` field is used to define scripts that can be run in the package's context. Turborepo will use the name of these scripts to identify what scripts to run (if any) in a package. We talk more about these scripts on the [Running Tasks](/repo/docs/crafting-your-repository/running-tasks) page.
#### `exports`
[The `exports` field](https://nodejs.org/api/packages.html#exports) is used to specify the entrypoints for other packages that want to use the package. When you want to use code from one package in another package, you'll import from that entrypoint.
For example, if you had a `@repo/math` package, you might have the following `exports` field:
```json title="./packages/math/package.json"
{
"exports": {
".": "./src/constants.ts",
"./add": "./src/add.ts",
"./subtract": "./src/subtract.ts"
}
}
```
Note that this example uses the [Just-in-Time Package](/repo/docs/core-concepts/internal-packages#just-in-time-packages) pattern for simplicity. It exports TypeScript directly, but you might choose to use the [Compiled Package](/repo/docs/core-concepts/internal-packages#compiled-packages) pattern instead.
The `exports` field in this example requires modern versions of Node.js and
TypeScript.
This would allow you to import `add` and `subtract` functions from the `@repo/math` package like so:
```ts title="./apps/my-app/src/index.ts"
import { GRAVITATIONAL_CONSTANT, SPEED_OF_LIGHT } from '@repo/math';
import { add } from '@repo/math/add';
import { subtract } from '@repo/math/subtract';
```
Using exports this way provides three major benefits:
* **Avoiding barrel files**: Barrel files are files that re-export other files in the same package, creating one entrypoint for the entire package. While they might appear convenient, they're [difficult for compilers and bundlers to handle](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js#what's-the-problem-with-barrel-files) and can quickly lead to performance problems.
* **More powerful features**: `exports` also has other powerful features compared to [the `main` field](https://nodejs.org/api/packages.html#main) like [Conditional Exports](https://nodejs.org/api/packages.html#conditional-exports). In general, we recommend using `exports` over `main` whenever possible as it is the more modern option.
* **IDE autocompletion**: By specifying the entrypoints for your package using `exports`, you can ensure that your code editor can provide auto-completion for the package's exports.
#### `imports` (optional)
[The `imports` field](https://nodejs.org/api/packages.html#imports) gives you a way to create subpaths to other modules within your package. You can think of these like "shortcuts" to write simpler import paths that are more resilient to refactors that move files. To learn how, visit [the TypeScript page](/repo/docs/guides/tools/typescript#use-nodejs-subpath-imports-instead-of-typescript-compiler-paths).
You may be more familiar with TypeScript's `compilerOptions#paths` option, which accomplishes a similar goal. As of TypeScript 5.4, TypeScript can infer subpaths from `imports`, making it a better option since you'll be working with Node.js conventions. For more information, visit [our TypeScript guide](/repo/docs/guides/tools/typescript#use-nodejs-subpath-imports-instead-of-typescript-compiler-paths).
### Source code
Of course, you'll want some source code in your package. Packages commonly use an `src` directory to store their source code and compile to a `dist` directory (that should also be located within the package), although this is not a requirement.
## Common pitfalls
* If you're using TypeScript, you likely don't need a `tsconfig.json` in the root of your workspace. Packages should independently specify their own configurations, usually building off of a shared `tsconfig.json` from a separate package in the workspace. For more information, visit [the TypeScript guide](/repo/docs/guides/tools/typescript#you-likely-dont-need-a-tsconfigjson-file-in-the-root-of-your-project).
* You want to avoid accessing files across package boundaries as much as possible. If you ever find yourself writing `../` to get from one package to another, you likely have an opportunity to re-think your approach by installing the package where it's needed and importing it into your code.
## Next steps
With your Workspace configured, you can now use your package manager to [install dependencies into your packages](/repo/docs/crafting-your-repository/managing-dependencies).
file: ./content/repo-docs/crafting-your-repository/understanding-your-repository.mdx
meta: {
"title": "Understanding your repository",
"description": "Learn how to understand your repository structure using Turborepo."
}
Turborepo includes tools for understanding your repository structure, that can help you use and optimize your codebase.
## `turbo ls`
To list your packages, you can run `turbo ls`. This will show the packages in your repository and where they're located.
```bash title="Terminal"
> turbo ls
turbo 2.1.3
WARNING ls command is experimental and may change in the future
5 packages (pnpm9)
@repo/eslint-config packages/eslint-config
@repo/typescript-config packages/typescript-config
@repo/ui packages/ui
docs apps/docs
web apps/web
```
You can [apply filters](/repo/docs/crafting-your-repository/running-tasks#using-filters) to `ls`, just like `run`:
```bash title="Terminal"
> turbo ls --filter ...ui
3 packages (pnpm9)
@repo/ui packages/ui
docs apps/docs
web apps/web
```
## `turbo run`
To determine which tasks can be run in your monorepo, simply call `turbo run` without any tasks. You will get a list of
tasks and the packages in which they are defined:
```bash title="Terminal"
> turbo run
No tasks provided, here are some potential ones
lint
@repo/ui, docs, web
build
docs, web
dev
docs, web
start
docs, web
generate:component
@repo/ui
```
## `turbo query`
If you wish to dig into your repository structure, since `2.2.0`, Turbo provides a GraphQL interface into your repository
via `turbo query`. You can execute queries such as finding all packages that have a `test` task:
```bash title="Terminal"
> turbo query "query { packages(filter: { has: { field: TASK_NAME, value: \"build\"}}) { items { name } } }"
{
"data": {
"packages": {
"items": [
{
"name": "//"
},
{
"name": "docs"
},
{
"name": "web"
}
]
}
}
}
```
This can be helpful for diagnosing potential problems in your package or task dependency graph. For instance, let's say
you're getting a lot of cache misses in your builds. This could be because there's a package that keeps getting changed
and is imported throughout your codebase.
To do this, we can run a query to find packages that are directly imported more than 10 times in your monorepo:
```bash title="Terminal"
> turbo query "query { packages(filter: { greaterThan: { field: DIRECT_DEPENDENT_COUNT, value: 10 } }) { items { name } } }"
{
"data": {
"packages": {
"items": [
{
"name": "utils"
}
]
}
}
}
```
Now that we've found this package, we can try to split it up into smaller packages so that a small change won't
invalidate the whole dependency graph.
Or let's say you're using our new `--affected` flag, but you're still running more tasks than you'd like.
With `turbo query`, you can find all the packages and the reason why they were invalidated:
```bash title="Terminal"
> turbo query "query { affectedPackages(base: \"HEAD^\", head: \"HEAD\") { items { reason { __typename } } } }"
{
"data": {
"affectedPackages": {
"items": [
{
"name": "utils",
"reason": {
"__typename": "FileChanged"
}
},
{
"name": "web",
"reason": {
"__typename": "DependencyChanged"
}
},
{
"name": "docs",
"reason": {
"__typename": "DependencyChanged"
}
},
{
"name": "cli",
"reason": {
"__typename": "DependencyChanged"
}
},
]
}
}
}
```
file: ./content/repo-docs/crafting-your-repository/upgrading.mdx
meta: {
"title": "Upgrading",
"description": "Learn how to upgrade `turbo` to get the latest improvements to your repository."
}
import { PackageManagerTabs, Tab } from '#/components/tabs';
import { Steps, Step } from '#/components/steps';
import { Callout } from '#/components/callout';
## Upgrading to 2.0
### Update `turbo.json`
Get started upgrading from 1.x to 2.0 by running:
```bash title="Terminal"
npx @turbo/codemod migrate
```
```bash title="Terminal"
yarn dlx @turbo/codemod migrate
```
```bash title="Terminal"
pnpm dlx @turbo/codemod migrate
```
This will update your `turbo.json`(s) for many of the breaking changes from 1.x to 2.0.
Additionally, a `name` field will be added to any `package.json` in the Workspace that doesn't have one.
You may also manually run each codemod individually. Visit [the codemods
page](/repo/docs/reference/turbo-codemod#turborepo-2x) for more information.
### Add a `packageManager` field to root `package.json`
[The `packageManager` field](https://nodejs.org/api/packages.html#packagemanager) is a convention from the Node.js ecosystem that defines which package manager is expected to be used in the Workspace.
Turborepo 2.0 requires that your Workspace define this field as a way to improve the stability and behavioral predictability of your codebase. If you do not have one already, add this field to your root `package.json`:
```diff title="./package.json"
{
+ "packageManager": "npm@10.8.1"
}
```
```diff title="./package.json"
{
+ "packageManager": "yarn@1.22.19"
}
```
```diff title="./package.json"
{
+ "packageManager": "pnpm@9.2.0"
}
```
### Update `eslint-config-turbo`
[`eslint-config-turbo`](/repo/docs/reference/eslint-config-turbo) helps identify environment variables that need to be added to the [`env`](/repo/docs/reference/configuration#env) key for caching. If you're using it, make sure you update it to match your major version.
### Update `turbo run` commands
Turborepo 2.0 includes behavioral and correctness improvements with behavior of `turbo run` commands. Listed below is the summary of changes, which may or may not have an affect on your codebase:
* Strict Mode for environment variables is now the default, moving from Loose Mode ([PR](https://github.com/vercel/turborepo/pull/8182))
* → If it appears that the scripts in your tasks are missing environment variables, you can opt back out of this behavior using [the `--env-mode` option](/repo/docs/reference/run#--env-mode-option) on a per-command basis to incrementally migrate. We encourage you to update [the `env` key](/repo/docs/reference/configuration#env) in your task to account for all of its environment variables so you can drop the `--env-mode` option as soon as possible.
* Workspace root directory is now an implicit dependency of all packages ([PR](https://github.com/vercel/turborepo/pull/8202))
* → The repository should have as little code in the root as possible, since changes to the root can affect all tasks in your repository. Additionally, if you're using [Internal Packages]() in the Workspace root, changes to those dependencies will also cause cache misses for all tasks. In both cases, consider moving the code out of the root and [into a package](/repo/docs/crafting-your-repository/structuring-a-repository).
* `--ignore` removed in favor of `--filter` and graph correctness changes below ([PR](https://github.com/vercel/turborepo/pull/8201))
* Removed `--scope` flag (deprecated since 1.2) ([PR](https://github.com/vercel/turborepo/pull/7970))
* `engines` field in root `package.json` is now used in hashing ([PR](https://github.com/vercel/turborepo/pull/8173))
* `--filter` no longer infers namespaces for package names ([PR](https://github.com/vercel/turborepo/pull/8137))
* `--filter` now errors when no package names or directories are matched ([PR](https://github.com/vercel/turborepo/pull/8142))
* `--only` restricts task dependencies instead of package dependencies ([PR](https://github.com/vercel/turborepo/pull/8163))
file: ./content/repo-docs/crafting-your-repository/using-environment-variables.mdx
meta: {
"title": "Using environment variables",
"description": "Learn how to handle environments for your applications."
}
import { Fragment } from 'react';
import { Callout } from '#/components/callout';
import { Tabs, Tab } from '#/components/tabs';
import { Accordion, Accordions } from '#/components/accordion';
import frameworks from '@turbo/types/src/json/frameworks.json';
Environment variable inputs are a vital part of your applications that you'll need to account for in your Turborepo configuration.
There are three important questions when working with environment variables in Turborepo:
* [Are my environment variables accounted for in the task hash?](#adding-environment-variables-to-task-hashes)
* [Which Environment Mode will `turbo` use?](#environment-modes)
* [Have I handled my `.env` files?](#handling-env-files)
Failing to account for environment variables in your configuration can result
in shipping your application with the wrong configuration. This can cause
serious issues like shipping your preview deployments to production.
Turborepo also uses [System Environment
Variables](/repo/docs/reference/system-environment-variables) to configure its
own behavior. Below, you'll find information about environment variables for
your task's runtime and how they affect task hashing.
## Adding environment variables to task hashes
Turborepo needs to be aware of your environment variables to account for changes in application behavior. To do this, use the `env` and `globalEnv` keys in your `turbo.json` file.
```json title="./turbo.json"
{
"globalEnv": ["IMPORTANT_GLOBAL_VARIABLE"],
"tasks": {
"build": {
"env": ["MY_API_URL", "MY_API_KEY"]
}
}
}
```
* **globalEnv**: Changes to the values of any environment variables in this list will change the hash for all tasks.
* **env**: Includes changes to the values of environment variables that affect the task, allowing for better granularity. For example, a `lint` task probably doesn't need to miss cache when the value of `API_KEY` changes, but a `build` task likely should.
Turborepo supports wildcards for environment variables so you can easily
account for all environment variables with a given prefix. Visit [the API
reference for `env`](/repo/docs/reference/configuration#wildcards) for more.
### Framework Inference
Turborepo automatically adds prefix wildcards to your [`env`](/repo/docs/reference/configuration#env) key for common frameworks. If you're using one of the frameworks below in a package, you don't need to specify environment variables with these prefixes:
Framework inference is per-package.
If you'd like to opt out of Framework Inference, you can do so by:
* Running your tasks with `--framework-inference=false`
* Adding a negative wildcard to the `env` key (for example, `"env": ["!NEXT_PUBLIC_*"]`)
## Environment Modes
Turborepo's Environment Modes allow you to control which environment variables are available to a task at runtime:
* [Strict Mode](#strict-mode) (Default): Filter environment variables to **only** those that are specified in the `env` and `globalEnv` keys in `turbo.json`.
* [Loose Mode](#loose-mode): Allow all environment variables for the process to be available.
### Strict Mode
Strict Mode filters the environment variables available to a task's runtime to **only** those that are specified in the `globalEnv` and `env` keys in `turbo.json`.
This means that tasks that do not account for all of the environment variables that they need are likely to fail. This is a good thing, since you don't want to cache a task that can potentially have different behavior in a different environment.
While Strict Mode makes it much more likely for your task to fail when you
haven't accounted for all of your environment variables, it doesn't guarantee
task failure. If your application is able to gracefully handle a missing
environment variable, you could still successfully complete tasks and get
unintended cache hits.
#### Passthrough variables
In advanced use cases, you may want to make some environment variables
available to a task without including them in the hash. Changes to these variables don't affect task outputs but still need to be available for the task to run successfully.
For these cases, add those environment variables to [`globalPassThroughEnv`](/repo/docs/reference/configuration#globalpassthroughenv) and [`passThroughEnv`](/repo/docs/reference/configuration#passthroughenv).
#### CI vendor compatibility
Strict Mode will filter out environment variables that come from your CI vendors until you've accounted for them using [`env`](/repo/docs/reference/configuration#env), [`globalEnv`](/repo/docs/reference/configuration#globalenv), [`passThroughEnv`](/repo/docs/reference/configuration#passthroughenv), or [`globalPassThroughEnv`](/repo/docs/reference/configuration#globalpassthroughenv).
If any of these variables are important to your tasks and aren't included by [Framework Inference](#framework-inference), make sure they are in your `turbo.json` configuration.
### Loose Mode
Loose Mode does not filter your environment variables according to your `globalEnv` and `env` keys. This makes it easier to get started with incrementally migrating to Strict Mode.
Use [the `--env-mode` flag](/repo/docs/reference/run#--env-mode-option) to enable Loose Mode on any invocation where you're seeing environment variables cannot be found by your scripts:
```bash title="Terminal"
turbo run build --env-mode=loose
```
As long as the environment variable is available when `turbo` is ran, your script will be able to use it. However, this also **lets you accidentally forget to account for an environment variable in your configuration much more easily**, allowing the task to hit cache when it shouldn't.
For example, you may have some code in your application that fetches data from an API, using an environment variable for the base URL:
```ts title="./apps/web/data-fetcher.ts"
const data = fetch(`${process.env.MY_API_URL}/resource/1`);
```
You then build your application using a value for `MY_API_URL` that targets your preview environment. When you're ready to ship your application, you build for production and see a cache hit - even though the value of the `MY_API_URL` variable has changed! `MY_API_URL` changed - but Turborepo restored a version of your application from cache that uses the preview environment's `MY_API_URL` rather than production's.
When you're using Loose Mode, `MY_API_URL` is available in the task runtime **even though it isn't accounted for in the task hash**. To make this task more likely to fail and protect you from this misconfiguration, we encourage you to opt for [Strict Mode](#strict-mode).
### Platform Environment Variables
When deploying your application to [Vercel](https://vercel.com/new?ref=turborepo), you likely already have [environment variables](https://vercel.com/docs/projects/environment-variables) configured on your project. Turborepo will automatically check these variables against your `turbo.json` configuration to ensure that you've [accounted for them](/repo/docs/crafting-your-repository/using-environment-variables#adding-environment-variables-to-task-hashes),
and will warn you about any missing variables.
This functionality can be disabled by setting `TURBO_PLATFORM_ENV_DISABLED=false`
## Handling `.env` files
`.env` files are great for working on an application locally. **Turborepo does not load .env files into your task's runtime**, leaving them to be handled by your framework, or tools like [`dotenv`](https://www.npmjs.com/package/dotenv).
However, it's important that `turbo` knows about changes to values in your `.env` files so that it can use them for hashing. If you change a variable in your `.env` files between builds, the `build` task should miss cache.
To do this, add the files to the [`inputs`](/repo/docs/reference/configuration#inputs) key:
```json title="./turbo.json"
{
"globalDependencies": [".env"], // All task hashes
"tasks": {
"build": {
"inputs": ["$TURBO_DEFAULT$", ".env", ".env.local"] // Only the `build` task hash
}
}
}
```
`.env` files can load variables into the task runtime even when the
environment variables have not been added to [the `env`
key](/repo/docs/reference/configuration#env). Ensure that you add your
environment variables for your builds the `env` key for CI and production
builds.
## Best practices
### Use `.env` files in packages
Using a `.env` file at the root of the repository is not recommended. Instead, we recommend placing your `.env` files into the packages where they're used.
This practice more closely models the runtime behavior of your applications since environment variables exist in each application's runtime individually. Additionally, as your monorepo scales, this practice makes it easier to manage each application's environment, preventing environment variable leakage across applications.
You may find it easier to use a root `.env` file when incrementally migrating
to a monorepo. Tools like [dotenv](https://www.npmjs.com/package/dotenv) can
load `.env` files from different locations.
### Use `eslint-config-turbo`
[The `eslint-config-turbo` package](/repo/docs/reference/eslint-config-turbo) helps you find environment variables that are used in your code that aren't listed in your `turbo.json`. This helps ensure that all your environment variables are accounted for in your configuration.
### Avoid creating or mutating environment variables at runtime
Turborepo hashes the environment variables for your task at the beginning of the task. If you create or mutate environment variables during the task, Turborepo will not know about these changes and will not account for them in the task hash.
For instance, Turborepo will not be able to detect the inline variable in the example below:
```json title="./apps/web/package.json"
{
"scripts": {
"dev": "export MY_VARIABLE=123 && next dev"
}
}
```
`MY_VARIABLE` is being added to the environment *after* the `dev` task has started, so `turbo` will not be able to use it for hashing.
## Examples
Below are examples of proper environment variable configuration for a few popular frameworks:
The `turbo.json` below expresses:
* The `build` and `dev` tasks will have different hashes for changes to `MY_API_URL` and `MY_API_KEY`.
* The `build` and `dev` tasks use the same [file loading order as Next.js](https://nextjs.org/docs/app/building-your-application/configuring/environment-variables#environment-variable-load-order), with `.env` having the most precedence.
* The `test` task does not use environment variables, so the `env` key is omitted. (Depending on your testing structure, your `test` task may need an `env` key.)
```json title="./turbo.json"
{
"tasks": {
"build": {
"env": ["MY_API_URL", "MY_API_KEY"],
"inputs": [
"$TURBO_DEFAULT$",
".env.production.local",
".env.local",
".env.production",
".env"
]
},
"dev": {
"inputs": [
"$TURBO_DEFAULT$",
".env.development.local",
".env.local",
".env.development",
".env"
]
},
"test": {}
}
}
```
The `turbo.json` below expresses:
* The `build` and `dev` tasks will have different hashes for changes to `MY_API_URL` and `MY_API_KEY`.
* The `build` and `dev` tasks use the same [file loading order as Vite](https://vitejs.dev/guide/env-and-mode#env-files), with `.env` having the most precedence.
* The `test` task does not use environment variables, so the `env` key is omitted. (Depending on your testing structure, your `test` task may need an `env` key.)
```json title="./turbo.json"
{
"tasks": {
"build": {
"env": ["MY_API_URL", "MY_API_KEY"],
"inputs": [
"$TURBO_DEFAULT$",
".env.production.local",
".env.local",
".env.production",
".env"
]
},
"dev": {
"inputs": [
"$TURBO_DEFAULT$",
".env.development.local",
".env.local",
".env.development",
".env"
]
},
"test": {}
}
}
```
## Troubleshooting
### Use `--summarize`
[The `--summarize` flag](/repo/docs/reference/run#--summarize) can be added to your `turbo run` command to produce a JSON file summarizing data about your task. Checking the diff for the `globalEnv` and `env` key can help you identify any environment variables that may be missing from your configuration.
## Next steps
Once you've accounted for your environment variables, you're ready to start building the CI pipelines that build, check, and deploy your applications, at the speed of `turbo`.
file: ./content/repo-docs/getting-started/add-to-existing-repository.mdx
meta: {
"title": "Add to an existing repository",
"description": "Using Turborepo with your existing repository"
}
import { Tabs, Tab } from '#/components/tabs';
import { Callout } from '#/components/callout';
import { Step, Steps } from '#/components/steps';
Turborepo can be incrementally adopted in **any repository, single or multi-package**, to speed up the developer and CI workflows of the repository.
After installing `turbo` and configuring your tasks in `turbo.json`, you'll notice how [caching](/repo/docs/crafting-your-repository/caching) helps you run tasks much faster.
## Preparing a single-package workspace
A [single-package workspace](https://vercel.com/docs/vercel-platform/glossary#single-package-workspace) is, for example, what you get after running `npx create-next-app` or `npm create vite`. You don't need to do any extra work for Turborepo to handle your repo so you can jump to the first step below.
To learn more about Turborepo in single-package workspaces, visit [the dedicated guide](/repo/docs/guides/single-package-workspaces).
## Preparing a multi-package workspace (monorepo)
`turbo` is built on top of Workspaces, a feature of the major package managers in the JavaScript ecosystem. This makes it easy to adopt in your existing codebase.
If you're finding that `turbo` is having issues like not being able to
discover packages in your workspace or not following your dependency graph,
visit our [Structuring a
repository](/repo/docs/crafting-your-repository/structuring-a-repository) page
for tips.
Note that you don't have to start running *all* your tasks for *all* your
packages using `turbo` right away. You can start with a single task in just a
few packages and incrementally add more tasks and packages as you get more
familiar with Turborepo.
## Adding Turborepo to your repository
### Install `turbo`
We recommend you install `turbo` both globally and into your repository's root for the best developer experience.
```bash title="Terminal"
# Global install
npm install turbo --global
# Install in repository
npm install turbo --save-dev
```
```bash title="Terminal"
# Global install
yarn global add turbo
# Install in repository
yarn add turbo --dev
```
```bash title="Terminal"
# Global install
pnpm add turbo --global
# Install in repository
pnpm add turbo --save-dev --workspace-root
```
To learn more about why we recommend both installations, visit the [Installation page](/repo/docs/getting-started/installation).
### Add a `turbo.json` file
In the root of your repository, create a `turbo.json` file.
We'll be using `build` and `check-types` tasks in this guide but you can replace these with other tasks that interest you, like `lint` or `test`.
```json title="./turbo.json"
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**"]
},
"check-types": {
"dependsOn": ["^check-types"]
},
"dev": {
"persistent": true,
"cache": false
}
}
}
```
For more information on configuring your `turbo.json`, see the [Configuration Options](/repo/docs/reference/configuration) documentation.
In your Next.js application, make sure you have a `check-types` script for `turbo` to run.
```diff title="apps/web/package.json"
{
"scripts": {
+ "check-types": "tsc --noEmit"
}
}
```
```json title="./turbo.json"
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"outputs": ["dist/**"]
},
"check-types": {
"dependsOn": ["^check-types"]
},
"dev": {
"persistent": true,
"cache": false
}
}
}
```
Some Vite starters ship with a `package.json` that looks like this:
```json title="package.json"
{
"scripts": {
"build": "tsc && vite build"
}
}
```
We recommend splitting these into a `check-types` and `build` script so that `turbo` can run them in parallel.
```json title="apps/web/package.json"
{
"scripts": {
"build": "vite build",
"check-types": "tsc --noEmit"
}
}
```
In a multi-package workspace, you may also want to add a `check-types` script
to one or more of your library packages to see how multiple scripts across
different packages run with one `turbo` command.
### Edit `.gitignore`
Add `.turbo` to your `.gitignore` file. The `turbo` CLI uses these folders for persisting logs, outputs, and other functionality.
```diff title=".gitignore"
+ .turbo
```
### Add a `packageManager` field to root `package.json`
Turborepo optimizes your repository using information from your package manager. To declare which package manager you're using, add a [`packageManager`](https://nodejs.org/api/packages.html#packagemanager) field to your root `package.json` if you don't have one already.
```diff title="package.json"
{
+ "packageManager": "npm@8.5.0"
}
```
Depending on your repository, you may need to use the
[`dangerouslyDisablePackageManagerCheck`](/repo/docs/reference/configuration#dangerouslydisablepackagemanagercheck)
while migrating or in situations where you can't use the `packageManager` key
yet.
### Run tasks with `turbo`
You can now run the tasks you added to `turbo.json` earlier using Turborepo. Using the example tasks from above:
```bash title="Terminal"
turbo build check-types
```
This runs the `build` and `check-types` tasks at the same time. The dependency graph of your [Workspace](/repo/docs/crafting-your-repository/structuring-a-repository#anatomy-of-a-workspace) will be used to run tasks in the right order.
**Without making any changes to the code, try running `build` and `check-types` again:**
```bash title="Terminal"
turbo check-types build
```
You should see terminal output like this:
```bash title="Terminal"
Tasks: 2 successful, 2 total
Cached: 2 cached, 2 total
Time: 185ms >>> FULL TURBO
```
Congratulations! **You just built and type checked your code in milliseconds**.
To learn more about how `turbo` makes this possible, check out [the caching documentation](/repo/docs/crafting-your-repository/caching).
### Begin developing by running `dev` with `turbo`
In a multi-package workspace, you can run `turbo dev` to start the development tasks for all your packages at once.
```bash title="Terminal"
turbo dev
```
You can also [use a filter](/repo/docs/crafting-your-repository/running-tasks#using-filters) to focus on a specific package and its dependencies.
Note that this step doesn't provide much value in a single-package workspace since:
* You don't cache the outputs for a development task.
* There's only one development script so there's nothing to run in parallel.
## Next steps
You're now up and running with Turborepo! To learn about more ways you can improve your workflow and get the most out of `turbo`, we recommend checking out the following pages:
* [Enabling Remote Caching for development machines](/repo/docs/crafting-your-repository/constructing-ci#enabling-remote-caching)
* [Enabling Remote Caching in CI](/repo/docs/crafting-your-repository/constructing-ci)
* [Handling environment variables](/repo/docs/crafting-your-repository/using-environment-variables)
* [Filtering tasks](/repo/docs/reference/run#--filter-string)
file: ./content/repo-docs/getting-started/editor-integration.mdx
meta: {
"title": "Editor integration",
"description": "Making the most of Turborepo"
}
import { Callout } from '#/components/callout';
To get the best experience with `turbo`, Turborepo provides a few utilities for integrating with your editor.
## JSON Schema for `turbo.json`
Turborepo uses [JSON Schema](https://json-schema.org/) to give you auto-complete in your
`turbo.json` file. By including the `$schema` key in your `turbo.json`, your editor is able to
provide full documentation and linting in case you have invalid shapes or missing keys.
### Sourcing from the web
A `schema.json` is accessible at the URL shown below. This has the advantage of not needing to run your package manager's install command to see in-editor validation.
```json title="./turbo.json"
{
"$schema": "https://turbo.build/schema.json"
}
```
There is also a major versioned `schema.json` available, following the format of `https://turbo.build/schema..json`.
```json title="./turbo.json"
{
"$schema": "https://turbo.build/schema.v1.json"
}
```
### Sourcing from `node_modules`
Starting in Turborepo 2.4, `schema.json` is available in `node_modules` once you've run your package manager's install command:
```json title="turbo.json"
{
"$schema": "./node_modules/turbo/schema.json"
}
```
We recommend installing `turbo` at the root of your repository, so the path
for the schema should point to `node_modules` at the root of your repository.
In [Package Configurations](/repo/docs/reference/package-configurations), you
may need to use a path like `../../node_modules/turbo/schema.json`.
## Linting for environment variables
Handling environment variables is an important part of building applications in a Turborepo.
[The `eslint-config-turbo` package](/repo/docs/reference/eslint-config-turbo) extends your ESLint setup to help you make sure you've taken care of all of your environment variables.
## Turborepo LSP
Enable even more auto-complete and linting than provided by JSON Schema, with in-editor hinting for invalid globs, references to non-existent tasks or packages, and
extra repository visibility tools.
Visit the [VSCode Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=Vercel.turbo-vsc) to install.
The language server can be used on any editors that support the [Language
Server Protocol](https://microsoft.github.io/language-server-protocol/). Log a
request in our [issue tracker](https://github.com/vercel/turborepo/issues) to
express your interest.
file: ./content/repo-docs/getting-started/examples.mdx
meta: {
"title": "Start with an example",
"description": "Start with an example Turborepo."
}
import { PackageManagerTabs, Tabs, Tab } from '#/components/tabs';
import { ExamplesTable } from '#/components/examples-table';
import { Callout } from '#/components/callout';
Use `create-turbo` to bootstrap an example with your favorite tooling.
```bash title="Terminal"
# Use an example listed below
npx create-turbo@latest --example [example-name]
# Use a GitHub repository from the community
npx create-turbo@latest --example [github-url]
```
```bash title="Terminal"
# Use an example listed below
yarn dlx create-turbo@latest --example [example-name]
# Use a GitHub repository from the community
yarn dlx create-turbo@latest --example [github-url]
```
```bash title="Terminal"
# Use an example listed below
pnpm dlx create-turbo@latest --example [example-name]
# Use a GitHub repository from the community
pnpm dlx create-turbo@latest --example [github-url]
```
## Core-maintained examples
This list is maintained by the Turborepo core team. Dependencies are kept as up-to-date as possible and GitHub Issues are accepted and addressed for these examples.
## Community-maintained examples
The community curates a set of examples to showcase ways to use common tools and libraries with Turborepo. To bootstrap your monorepo with one of the examples, use the `--example` flag:
GitHub Issues for these examples will be closed. If you find problems, please
submit a pull request with fixes.
file: ./content/repo-docs/getting-started/index.mdx
meta: {
"title": "Getting started",
"description": "Get started with Turborepo."
}
import { Card, Cards } from '#/components/card';
import { Step, Steps } from '#/components/steps';
import { Tab, Tabs } from '#/components/tabs';
If you're new to Turborepo, you can follow these steps to get started.
## Install Turborepo
Install `turbo` globally so you can conveniently run `turbo` commands in your terminal from anywhere in your repository.
```bash title="Terminal"
npm install turbo --global
```
```bash title="Terminal"
yarn global add turbo
```
```bash title="Terminal"
pnpm install turbo --global
```
To learn more about installing `turbo`, see the [installation guide](/repo/docs/getting-started/installation).
## Choose your learning path
file: ./content/repo-docs/getting-started/installation.mdx
meta: {
"title": "Installation",
"description": "Learn how to get started with Turborepo."
}
import { Callout } from '#/components/callout';
import { PackageManagerTabs, Tabs, Tab } from '#/components/tabs';
Get started with Turborepo in a few moments using:
```bash title="Terminal"
npx create-turbo@latest
```
```bash title="Terminal"
yarn dlx create-turbo@latest
```
```bash title="Terminal"
pnpm dlx create-turbo@latest
```
The starter repository will have:
* Two deployable applications
* Three shared libraries for use in the rest of the monorepo
For more details on the starter, [visit the README for the basic starter on GitHub](https://github.com/vercel/turborepo/tree/main/examples/basic). You can also [use an example](/repo/docs/getting-started/examples) that more closely fits your tooling interests.
## Installing `turbo`
`turbo` can be installed both globally **and** in your repository. We highly recommend installing both ways so you can take advantage of fast, convenient workflows *and* a stable version of `turbo` for all developers working in your repository.
### Global installation
A global install of `turbo` brings flexibility and speed to your local workflows.
```bash title="Terminal"
npm install turbo --global
```
```bash title="Terminal"
yarn global add turbo
```
```bash title="Terminal"
pnpm install turbo --global
```
Once installed globally, you can run your scripts through `turbo` from your terminal, quickly running one-off commands to use within your repository. For example:
* `turbo build`: Run `build` scripts following your repository's dependency graph
* `turbo build --filter=docs --dry`: Quickly print an outline of the `build` task for your `docs` package (without running it)
* `turbo generate`: Run [Generators](/repo/docs/guides/generating-code) to add new code to your repository
* `cd apps/docs && turbo build`: Run the `build` script in the `docs` package and its dependencies. For more, visit the [Automatic Package Scoping section](/repo/docs/crafting-your-repository/running-tasks#automatic-package-scoping).
`turbo` is an alias for [`turbo run`](/repo/docs/reference/run). For example,
`turbo build` and `turbo run build` will both run your `build` task.
If you've installed global `turbo` before, make sure you use the same package
manager as your existing installation to avoid unexpected behaviors. You can
quickly check which package manager you previously used with [`turbo
bin`](/repo/docs/reference/bin).
#### Using global `turbo` in CI
You can also take advantage of global `turbo` when creating your CI pipelines. Visit the [Constructing CI](/repo/docs/crafting-your-repository/constructing-ci#global-turbo-in-ci) guide for more information.
### Repository installation
When collaborating with other developers in a repository, it's a good idea to pin versions of dependencies. You can do this with `turbo` by adding it as a `devDependency` in the root of your repository:
```bash title="Terminal"
npm install turbo --save-dev
```
```bash title="Terminal"
yarn add turbo --dev --ignore-workspace-root-check
```
```bash title="Terminal"
pnpm add turbo --save-dev --ignore-workspace-root-check
```
You can continue to use your global installation of `turbo` to run commands. Global `turbo` will defer to the local version of your repository if it exists.
This lets you to get the best of both installations: easily run commands in your terminal while maintaining a pinned version for consistent usage for all developers in the repository.
file: ./content/repo-docs/getting-started/support-policy.mdx
meta: {
"title": "Support policy",
"description": "Learn about Turborepo's Support policy."
}
import { Callout } from '#/components/callout';
## Package managers
Core `turbo` functionality depends on the package managers in the JavaScript ecosystem and their implementations of Workspaces and
lockfiles formats.
| Package manager | Supported |
| --------------- | ------------------------------- |
| pnpm 8+ | Yes |
| npm 8+ | Yes |
| yarn 1+ | Yes (Includes Yarn Plug'n'Play) |
| bun 1+ | Beta |
Package managers have their own release schedules, bugs, and features. While
we intend to keep up with new major versions, we likely will not be able to
release support immediately.
## Platforms
`turbo` is generally supported on Debian-based Linux distributions, macOS, and
Windows on both x86\_64 and ARM 64 architectures. Specifically, we build and ship
the following binaries via npm:
* `turbo-darwin-64` (macOS with Intel chips)
* `turbo-darwin-arm64` (macOS with Apple Silicon)
* `turbo-linux-64`
* `turbo-linux-arm64`
* `turbo-windows-64`\*
* `turbo-windows-arm64`\*
\*: Requires [Windows C Runtime
Libraries](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist)
## Node.js
Core `turbo` functionality does not depend on the
active Node.js version on your system, but [some packages in the Turborepo ecosystem](/repo/docs/reference#packages)
such as [`create-turbo`](/repo/docs/reference/create-turbo), [`turbo-ignore`](/repo/docs/reference/turbo-ignore), and [`eslint-config-turbo`](/repo/docs/reference/eslint-config-turbo) do. For these features,
we intend to support the [Active and Maintenance LTS versions of Node.js](https://nodejs.org/en/about/previous-releases).
Turborepo's [examples](/repo/docs/getting-started/examples) are also expected to work with these Node.js versions.
## Version control
We support repositories that are version controlled with Git and repositories that don't have
version control at all. Any other version control system will be ignored.
Note that we use Git to hash files, so repositories without git may perform and behave differently.
## LTS policy
Major versions of Turborepo will be supported for two years from the release date of the next major version.
Changes required for critical security fixes in older versions will be backported. Such situations will be rare and will land as semver-minor releases, even if they are breaking changes.
We highly encourage you to use the most current version of Turborepo whenever possible.
| Major version | Release date | End-of-life date |
| ------------- | ------------ | ---------------- |
| 2.x | Jun. 4, 2024 | |
| 1.x | Dec. 9, 2021 | Jun. 4, 2026 |
file: ./content/repo-docs/guides/generating-code.mdx
meta: {
"title": "Generating code",
"description": "Learn how to generate code using Turborepo."
}
import { Callout } from '#/components/callout';
import { File, Folder, Files } from '#/components/files';
import { PackageManagerTabs, Tab } from '#/components/tabs';
Splitting your monorepo into packages is a great way to organize your code, speed up tasks, and improve the local development
experience. With Turborepo's code generation, it's easy to generate new source code for packages, modules,
and even individual UI components in a structured way that integrates with the rest of your repository.
## Add an empty package
Add a new, empty app or package to your monorepo.
```sh title="Terminal"
turbo gen workspace
```
View all available [options](/repo/docs/reference/generate#workspace) for `gen workspace`.
## Copy an existing package
You can use an existing workspace as a template for your new app or package. This works for both workspaces within your existing monorepo,
and remote workspaces from other repositories (specified via GitHub URL).
### Examples
Create a new package in your monorepo by copying from an existing package in your repo.
```sh title="Terminal"
turbo gen workspace --copy
```
Create a new workspace in your monorepo by copying from a remote package.
```sh title="Terminal"
turbo gen workspace --copy https://github.com/vercel/turborepo/tree/main/examples/with-tailwind/packages/tailwind-config
```
**Note**: When adding from a remote source, Turborepo is unable to verify that your repo has all of the required dependencies, and is using the correct package manager. In this case, some manual modifications may be required to get the new workspace working as expected within your repository.
View all available [options](/repo/docs/reference/generate#workspace) for `gen workspace --copy`.
## Custom generators
If a built-in generator does not fit your needs, you can create your own custom generator using [Plop](https://plopjs.com/) configurations.
Turborepo will automatically detect any generator configurations within your repo, and make them available to run from the command line.
While Turborepo Generators are built on top of Plop, they don't require `plop`
to be installed as a dependency in your repo.
While Turborepo understands all Plop configuration options and features, it provides a few additional features to improve the experience of writing
generators within a repo configured with Turborepo.
1. Generators are automatically discovered, loaded, and organized per workspace (no need to manually `load` them within a single configuration file)
2. Generators are automatically run from the root of the workspace where they are defined
3. Generators can be invoked from anywhere within your repo (or outside out it via the [`--root`](/repo/docs/reference/generate#--root-path) flag)
4. TypeScript generators are supported with zero configuration
5. `plop` is not required to be installed as a dependency of your repo
ESM dependencies are not currently supported within custom generators.
### Getting started
To build and run a custom generator, run the following command from anywhere within your monorepo using Turborepo.
```sh title="Terminal"
turbo gen
```
You'll be prompted to select an existing generator or to create one if you don't have any yet. You can also create your configuration
manually at `turbo/generators/config.ts` (or `config.js`) at the root of your repo - or within *any* workspace.
If you are using TypeScript, you will need to install [the `@turbo/gen`
package](https://github.com/vercel/turborepo/tree/main/packages/turbo-gen) as
a `devDependency` to access the required TS types.
For example, the following illustrates a monorepo with three locations for generators:
Generators created within workspaces are automatically run from the workspace root, **not** the repo root, nor the location of the generator configuration.
This makes your generators more simple to write. Creating a file at `[workspace-root]` only needs to be specified as `` rather than `../../`.
Learn more about [creating custom generators using Plop](https://plopjs.com/documentation/#creating-a-generator).
### Writing generators
A generator configuration file is a function that returns a [Plop](https://plopjs.com/) configuration object. The configuration object is
used to define the generator's prompts, and actions.
In its simplest form, a generator configuration file looks like:
```ts title="turbo/generators/config.ts"
import type { PlopTypes } from "@turbo/gen";
export default function generator(plop: PlopTypes.NodePlopAPI): void {
// create a generator
plop.setGenerator("Generator name", {
description: "Generator description",
// gather information from the user
prompts: [
...
],
// perform actions based on the prompts
actions: [
...
],
});
}
```
#### Prompts
Prompts are written using [Plop prompts](https://plopjs.com/documentation/#using-prompts) and are used to gather information from the user.
#### Actions
Actions can use [built-in Plop actions](https://plopjs.com/documentation/#built-in-actions), or [custom action functions](https://plopjs.com/documentation/#functionsignature-custom-action) that you define yourself:
```ts title="turbo/generators/config.ts"
import type { PlopTypes } from "@turbo/gen";
const customAction: PlopTypes.CustomActionFunction = async (answers) => {
// fetch data from a remote API
const results = await fetchRemoteData();
// add the response to the answers, making this data available to actions
answers.results = results;
// return a status string
return 'Finished data fetching!';
}
export default function generator(plop: PlopTypes.NodePlopAPI): void {
// create a generator
plop.setGenerator("Generator name", {
description: "Generator description",
prompts: [
...
],
actions: [
customAction
{/* actions now have access to `answers.results` */}
...
],
});
}
```
### Running generators
Once you have created your generator configuration file, you can skip the selection prompt and directly run a specified generator with:
```sh title="Terminal"
turbo gen [generator-name]
```
Arguments can also be passed directly to the generator prompts using `--args`
```sh title="Terminal"
turbo gen [generator-name] --args answer1 answer2 ...
```
See [bypassing prompts](https://plopjs.com/documentation/#bypassing-prompts) in the Plop documentation for more information.
View all available [options](/repo/docs/reference/generate#run-generator-name) for `gen`.
file: ./content/repo-docs/guides/handling-platforms.mdx
meta: {
"title": "Handling platforms",
"description": "Learn how to handle caching around operating systems, architectures, and other arbitrary conditions for Turborepo tasks."
}
## Node.js versions
To account for Node.js versions, use [the engines key in package.json](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines). Turborepo will account for changes to this field and miss cache accordingly.
## Operating systems, architecture, and other arbitrary conditions
For advanced use cases, you may want the operating system (OS), architecture, or other external factors to contribute to your hash.
### 1. Write an arbitrary file to disk
First, create a script that accounts for the hash contributors that you are interested in. For example, here is a Node.js script that identifies platform and architecture and writes those details to a file (`turbo-cache-key.json`):
```js title="./scripts/create-turbo-cache-key.js"
#!/usr/bin/env node
const { writeFileSync } = require('fs');
const { join } = require('path');
const { platform, arch } = process;
const file = 'turbo-cache-key.json';
const str = JSON.stringify({ platform, arch });
console.log(`Generating cache key: ${str}`);
writeFileSync(file, str);
```
### 2. Add the file to your .gitignore
You won't want to commit this file to source control since it's dependent on environment. Add it to your `.gitignore`:
```diff title=".gitignore"
+ turbo-cache-key.json
```
### 3. Add the file to the hash
Now, make sure that `turbo` is aware of the file by adding it to task inputs. You can do this two ways:
* **For specific tasks**: Include the file in [the `inputs` array](/repo/docs/reference/configuration#inputs) of the task(s):
```json title="./turbo.json"
{
"tasks": {
"build-for-platforms": {
"dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT$", "turbo-cache-key.json"]
}
}
}
```
* **For all tasks**: Add the file to [`globalDependencies`](/repo/docs/reference/configuration#globaldependencies)
```json title="./turbo.json"
{
"globalDependencies": ["turbo-cache-key.json"],
"tasks": {
...
}
}
```
### 4. Generate the file before running `turbo`
Last, you'll want to ensure that you run the script before running `turbo`. For example:
```json title="./package.json"
{
"scripts": {
"build-for-platforms": "node ./scripts/create-turbo-cache-key.js && turbo run build"
}
}
```
`turbo run build` will now take into account the contents of `turbo-cache-key.json` when calculating the hash for the `build` task.
file: ./content/repo-docs/guides/index.mdx
meta: {
"title": "Guides",
"description": "Learn how to use your favorite tooling in a Turborepo."
}
import { Cards, Card } from '#/components/card';
Turborepo works with your favorite frameworks, CI providers, tools, and use cases.
In our community-supported guides, you'll find examples of how to use `turbo` with the rest of your tooling.
file: ./content/repo-docs/guides/migrating-from-nx.mdx
meta: {
"title": "Migrating from Nx",
"description": "Learn how to migrate to Turborepo from Nx."
}
import { PackageManagerTabs, Tabs, Tab } from '#/components/tabs';
This guide will help you migrate an existing Nx repository to Turborepo.
* Explore key concepts by [migrating from an Nx starter to Turborepo](#migration-steps)
* Considerations for [more complex migration scenarios](#advanced-migration-considerations)
## Why switch?
There are many reasons why you may be choosing to migrate from Nx to Turborepo. Below, we've listed the most common motivations that developers have referenced for their migrations.
### Using ecosystem standards
Turborepo's goal is to be lightweight, leaning on your repository as the source of truth. An example of this is Turborepo being [built on top of JavaScript package manager workspaces](/repo/docs/crafting-your-repository/structuring-a-repository) for it's JavaScript/TypeScript support.
By contrast, Nx uses layers of plugins, dependencies, and other Nx-specific code to infer information about your repository. While these plugins can provide a layer of functionality and are optional, Nx users looking to migrate often cite removing Nx-specific code from their codebase as a key motivation for their change.
### Greater control of source code
Nx’s philosophy involves wrapping your code with layers of plugins, dependencies, and Nx-specific code. While these layers of code are optional, they provide a great deal of Nx's value and are recommended by Nx, so most Nx repos have them. When migrating to Turborepo, many developers explain that these layers tend to create a layer of obfuscation that abstracts their repository away from their control, causing issues.
Turborepo chooses to let you handle your tooling on your own terms, configuring (or not configuring) any of your tooling as you please.
### Less configuration for your repository manager
Migrating to Turborepo will likely require deleting previous configuration that you had for Nx and replacing it with less configuration for Turborepo, since Turborepo will automatically infer your repository's needs. For example, here are the tool-specific configurations you'll find in the equivalent starters for Turborepo and Nx [used below](#migration-steps).
```json title="turbo.json"
{
"$schema": "/schema.json",
"ui": "tui",
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": [".next/**", "!.next/cache/**"]
},
"lint": {
"dependsOn": ["^lint"]
},
"check-types": {
"dependsOn": ["^check-types"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
```
```json title="nx.json"
{
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": [
"default",
"!{projectRoot}/.eslintrc.json",
"!{projectRoot}/eslint.config.cjs",
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
"!{projectRoot}/tsconfig.spec.json",
"!{projectRoot}/jest.config.[jt]s",
"!{projectRoot}/src/test-setup.[jt]s",
"!{projectRoot}/test-setup.[jt]s"
],
"sharedGlobals": ["{workspaceRoot}/.github/workflows/ci.yml"]
},
"nxCloudId": "6789ec521d90a2165398f39a",
"plugins": [
{
"plugin": "@nx/next/plugin",
"options": {
"startTargetName": "start",
"buildTargetName": "build",
"devTargetName": "dev",
"serveStaticTargetName": "serve-static"
}
},
{
"plugin": "@nx/playwright/plugin",
"options": {
"targetName": "e2e"
}
},
{
"plugin": "@nx/eslint/plugin",
"options": {
"targetName": "lint"
}
},
{
"plugin": "@nx/jest/plugin",
"options": {
"targetName": "test"
}
}
],
"targetDefaults": {
"e2e-ci--**/*": {
"dependsOn": ["^build"]
}
},
"generators": {
"@nx/next": {
"application": {
"style": "tailwind",
"linter": "eslint"
}
}
}
}
```
```json title="project.json"
{
"name": "starter",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/starter",
"projectType": "application",
"tags": [],
"// targets": "to see all targets run: nx show project starter --web",
"targets": {}
}
```
### Free Remote Caching
Turborepo’s [Remote Caching](/repo/docs/core-concepts/remote-caching) stores the results of your task on a cloud server. This saves enormous amounts of time by **preventing duplicated work across your entire organization**. [Vercel Remote Cache](https://vercel.com/docs/monorepos/remote-caching) has saved teams over 500 years of compute so far.
Since Nx 19.7, similar functionality is a paid-for feature, even when self-hosting. Remote Caching with Turborepo is free when [self-hosting](/repo/docs/core-concepts/remote-caching#self-hosting) or using [Vercel Remote Cache](https://vercel.com/docs/monorepos/remote-caching).
## Migration steps
Our goal for this migration is to get a working Turborepo task as quickly as possible, so that you can adopt Turborepo features incrementally. We’ll start by using the Nx scaffolder to create a repository with a Next.js app.
```bash title="Terminal"
npx create-nx-workspace --preset=next --ci=skip --e2eTestRunner=none --style=tailwind --nextAppDir=true --nextSrcDir=false --packageManager=pnpm --appName=starter
```
### Step 1: Update .gitignore
Turborepo uses the .turbo directory to hold local caches and other information about your repository. For this reason, it should be added to your `.gitignore`.
```txt title=".gitignore"
.turbo
```
### Step 2: Add a workspace definition
Turborepo is built on top of package manager workspaces, a JavaScript ecosystem standard. Add the directory paths to the workspace that will contain packages.
```json title="package.json"
{
"workspaces": ["apps/*"]
}
```
```json title="package.json"
{
"workspaces": ["apps/*"]
}
```
```yml title="pnpm-workspace.yaml"
packages:
- apps/*
```
### Step 3: Add a package.json to the application
Rather than adding additional configuration files like `project.json`, Turborepo uses the standard `package.json` file.
Add a `package.json` to the `starter` application. Create a `package.json` at `./apps/starter/package.json` that contains a `dev` and `build` script.
```json title="./apps/starter/package.json"
{
"name": "starter",
"scripts": {
"dev": "next dev",
"build": "next build"
}
}
```
### Step 4: Remove Nx plugin
Remove the Nx plugin from ./apps/starter/next.config.js. The example file below doesn’t have configuration, though your existing Next.js application may need some.
```js title="./apps/starter/next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {};
module.exports = nextConfig;
```
### Step 5: Add the `packageManager` field
The root package.json needs to have the `packageManager` field. This ensures developers in the repository use the correct package manager, and that Turborepo can optimize your package graph based on your lockfile.
```json title="./package.json"
{
"packageManager": "npm@10.0.0"
}
```
```json title="./package.json"
{
"packageManager": "yarn@1.22.19"
}
```
```json title="./package.json"
{
"packageManager": "pnpm@9.0.0"
}
```
### Step 6: Run you package manager's install command
Update your lockfile by running your installation command.
```bash title="Terminal"
npm install
```
```bash title="Terminal"
yarn install
```
```bash title="Terminal"
pnpm install
```
Once you've done this, you should see a lockfile diff, indicating that the package has been added to the package manager's workspace.
### Step 7: Install Turborepo
Add Turborepo to the root `package.json` of the workspace.
```bash title="Terminal"
npm install turbo --save-dev
```
```bash title="Terminal"
yarn add turbo --save-dev --ignore-workspace-root-check
```
```bash title="Terminal"
pnpm install turbo --save-dev --workspace-root
```
You can also optionally install `turbo` globally for added convenience when working with Turborepo.
```bash title="Terminal"
npm install turbo --global
```
```bash title="Terminal"
yarn global add turbo
```
```bash title="Terminal"
pnpm install turbo --global
```
### Step 8: Add a `turbo.json`
Create a `turbo.json` at the root to register your tasks and describe their task dependencies.
```json title="./turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
```
### Step 9: Run `turbo build`
Build the application with Turborepo. Using global `turbo`, this would be `turbo build`. You can also run the command through your package manager:
```bash title="Terminal"
npx turbo run build
```
```bash title="Terminal"
yarn dlx turbo build
```
```bash title="Terminal"
pnpm exec turbo build
```
### Step 10: Enable Remote Caching (optional)
By default, Turborepo will connect to the free-to-use Vercel Remote Cache when you run:
```bash title="Terminal"
turbo login
turbo link
```
You may also configure a self-hosted Remote Cache, which does not require a license or any other fees.
## Advanced migration considerations
While the migration guide above is a good starting point, the breadth of possibilities and capabilities of monorepos means that its difficult to create generalized instructions for all cases. Below, we’ve listed some common next steps that you may be thinking about.
### Migrate complex monorepos incrementally
We encourage incremental migration, meaning you will have both of Nx and Turborepo in your repository at the same time. Make sure to spend time understanding how your Nx task graph is constructed. Splitting up the task graph may include strategies like:
* **Migrating one task at a time**: Changing `nx run lint` to `turbo run lint`
* **Migrating one package/project at a time**: Changing `nx run-many lint test --projects=web` to `turbo run lint test --filter=web`
* **Double-running some of your tasks**: To ensure stability, you may choose to run `turbo run lint` **and** `nx run lint` while you're still getting comfortable and builiding certainty in the early phases of your migration.
### Installing dependencies where they're used
Turborepo recommends [installing packages where they're used](/repo/docs/crafting-your-repository/managing-dependencies#best-practices-for-dependency-installation) to improve cache hit ratios, help dependency pruning capability, and clarify for developers which dependencies are meant for which packages. This is different from the Nx strategy, where all dependencies are installed at the root of the repository, making all dependencies available to all packages in the workspace.
Historically, Nx has recommended installing all dependencies in the root of the repository, making all dependencies available to all packages in the Workspace. If you followed this guidance, we highly recommend that you move dependencies to the `package.json`'s for packages and applications that need them. [Visit our documentation on managing dependencies](/repo/docs/crafting-your-repository/managing-dependencies) to learn more.
### Creating shared packages
You’ll follow roughly the same set of steps as above to add a package to your package manager’s workspace.
1. Ensure the package’s directory is included in the workspace definition (like `./packages/*` ).
2. Add a `package.json` to the package with the scripts it needs to run.
3. Check task dependencies in `turbo.json` to make sure your dependency graph meets your requirements.
### Multi-language monorepos
Turborepo natively supports JavaScript and TypeScript, with secondary support for any other languages you’d like to use. [Visit the Multi-Language support documentation](/repo/docs/guides/multi-language) to learn more.
## Configuration equivalents
Configuration found in `nx.json` can be mapped to `turbo.json` using the tables below.
The majorify of globs for capturing files are the same between Nx and
Turborepo. See [our file glob specification](/repo/docs/reference/globs) for
details and edge cases.
### Global configuration
| Nx | Turborepo |
| -------------------------- | ----------------------------------------------------------------------------- |
| `sharedGlobals` | [`globalDependencies`](/repo/docs/reference/configuration#globaldependencies) |
| `sharedGlobals.env` | [`globalEnv`](/repo/docs/reference/configuration#globalenv) |
| `sharedGlobals.namedInput` | [`globalDependencies`](/repo/docs/reference/configuration#globaldependencies) |
| `cacheDirectory` | [`cacheDir`](/repo/docs/reference/configuration#cachedir) |
### Task configuration
| Nx | Turborepo |
| --------------- | ------------------------------------------------------------------- |
| `inputs` files | [`tasks[task].inputs`](/repo/docs/reference/configuration#inputs) |
| `inputs.env` | [`tasks[task].env`](/repo/docs/reference/configuration#env) |
| `outputs` files | [`tasks[task].outputs`](/repo/docs/reference/configuration#outputs) |
| `cache` | [`tasks[task].cache`](/repo/docs/reference/configuration#cache) |
### CLI equivalents
| Nx | Turborepo |
| ---------------- | ---------------------------------------------------------------------------- |
| `nx generate` | [`turbo generate`](/repo/docs/reference/generate) |
| `nx run` | [`turbo run`](/repo/docs/reference/run) |
| `nx run-many` | [`turbo run`](/repo/docs/reference/run) |
| `nx reset` | [`--force`](/repo/docs/reference/run#--force) |
| `--parallel` | [`--concurrency`](/repo/docs/reference/run#--concurrency-number--percentage) |
| `--nxBail` | [`--continue`](/repo/docs/reference/run#--continue-option) |
| `--projects` | [`--filter`](/repo/docs/reference/run#--filter-string) |
| `--graph` | [`--graph`](/repo/docs/reference/run#--graph-file-type) |
| `--output-style` | [`--log-order`](/repo/docs/reference/run#--log-order-option) |
| `--no-cloud` | [`--cache`](/repo/docs/reference/run#--cache-options) |
| `--verbose` | [`--verbosity`](/repo/docs/reference/run#--verbosity) |
file: ./content/repo-docs/guides/multi-language.mdx
meta: {
"title": "Multi-language support",
"description": "Learn how to use multiple languages with Turborepo."
}
import { PackageManagerTabs, Tab } from '#/components/tabs';
import { LinkToDocumentation } from '#/components/link-to-documentation';
Turborepo is built on the conventions of the JavaScript ecosystem to find scripts and tasks to execute - but it doesn't care what those scripts do. Following [the guidance for specifying a package in a JavaScript workspace](/repo/docs/crafting-your-repository/structuring-a-repository#specifying-packages-in-a-monorepo), you can add any other language or toolchain to Turborepo.
As an example, you may have a Rust project in the `./cli` directory in your repository. To add this directory as a package to your JavaScript package manager's workspace, add the directory to the workspace definition:
```json title="./package.json"
{
"workspaces": [
"apps/*"
"packages/*",
"cli" // [!code highlight]
]
}
```
npm workspace documentation
```json title="./package.json"
{
"workspaces": [
"apps/*"
"packages/*",
"cli" // [!code highlight]
]
}
```
yarn workspace documentation
```json title="pnpm-workspace.yaml"
packages:
- "apps/*"
- "packages/*"
- "cli" // [!code highlight]
```
pnpm workspace documentation
Then, add a `package.json` to the directory:
```json title="./cli/package.json"
{
"name": "@repo/rust-cli",
"scripts": {
"build": "cargo build --release"
}
}
```
Now, when you use `turbo build`, the `"build"` script in `./cli/package.json` will be included into the tasks that `turbo` runs.
## Caching build artifacts
Ensure that the outputs for your builds are being cached with [the outputs key](/repo/docs/reference/configuration#outputs) in `turbo.json`. In the case of a Rust CLI being compiled with cargo, a release build would be created in the `target/release` directory and we can cache it using:
```json title="./turbo.json"
{
"tasks": {
"build": {
"outputs": ["target/release/**"] // [!code highlight]
}
}
}
```
## Creating dependency relationships
Because the directory is now a part of the package manager's workspace, you can create dependencies exactly the same as you do for your JavaScript packages.
For instance, if you wanted to make sure that the `rust-cli` "package" from above is built before your `web` application, install it into the dependencies for the `web` application:
```diff title="./web/package.json"
{
"devDependencies": {
+ "@repo/rust-cli": "*"
}
}
```
```diff title="./web/package.json"
{
"devDependencies": {
+ "@repo/rust-cli": "*"
}
}
```
```diff title="./web/package.json"
{
"devDependencies": {
+ "@repo/rust-cli": "workspace:*"
}
}
```
Given a `turbo.json` with a `build` task like:
```json title="./turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "target/release/**"]
}
}
}
```
`turbo build` will first create the artifacts for the Rust CLI and then build the `web` application.
file: ./content/repo-docs/guides/publishing-libraries.mdx
meta: {
"title": "Publishing libraries",
"description": "Learn how to publish libraries to the npm registry from a monorepo."
}
import { Callout } from '#/components/callout';
import { Tabs, Tab } from '#/components/tabs';
Publishing a package to the npm registry from a monorepo can be a smooth experience, with the right tools.
While this guide cannot solve for every possible compiling, bundling, and publishing configuration needed for robust packages, it will explain some of the basics.
You should follow this setup if you want to publish some of your monorepo's
packages to npm. If you don't need to publish to npm, you should use an
[Internal
Package](/repo/docs/crafting-your-repository/creating-an-internal-package)
instead. They're much easier to set up and use.
## Bundling
Unlike [Internal Packages](/repo/docs/crafting-your-repository/creating-an-internal-package), external packages can be deployed to [npm](https://www.npmjs.com) *and* used locally. In this guide, we'll bundle a package to both [ECMAScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) (`esm`) and [CommonJS modules](https://en.wikipedia.org/wiki/CommonJS) (`cjs`), the most commonly used formats on npm.
## Setting up a build script
Let's start with a package created using the [Internal Packages](/repo/docs/crafting-your-repository/creating-an-internal-package) tutorial.
There, we created a `@repo/math` package which contained a few helper functions for adding and subtracting numbers. We've decided that this package is good enough for npm, so we're going to bundle it.
We're going to add a `build` script to `@repo/math`, using a bundler. If you're unsure which one to choose, we recommend [`tsup`](https://tsup.egoist.dev/).
Install `tsup` inside the `./packages/math` package using your package manager and then create a build script for it:
```json title="./packages/math/package.json"
{
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts"
}
}
```
`tsup` outputs files to the `dist` directory by default, so you should:
1. Add `dist` to your `.gitignore` files to make sure they aren't committed to source control.
2. Add `dist` to the outputs of `build` in your `turbo.json`.
```json title="./turbo.json"
{
"tasks": {
"build": {
"outputs": ["dist/**"]
}
}
}
```
That way, when `tsup` is run the outputs can be [cached](/repo/docs/crafting-your-repository/caching) by Turborepo.
Finally, we should update our package entrypoints. Inside `package.json`, change `main` to point at `./dist/index.js` for clients using CommonJS modules (`cjs`), `module` to point at `./dist/index.mjs` for clients using ECMAScript modules (`esm`), and `types` to the type definition file - `./dist/index.d.ts`:
```json title="./packages/math/package.json"
{
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts"
}
```
It is not required to bundle to both `cjs` and `esm`. However, it is recommended, as it allows your package to be used in a wider variety of environments.
If you run into errors by using `main`, `module` and `types`, take a look at the [tsup docs](https://tsup.egoist.dev/#bundle-formats).
Bundling is a complicated topic, and we don't have space here to cover everything!
### Building our package before our app
Before we can run `turbo run build`, there's one thing we need to consider. We've just added a [task dependency](/repo/docs/crafting-your-repository/running-tasks) into our monorepo. The `build` of `packages/math` needs to run **before** the `build` of `apps/web`.
Fortunately, we can use [`dependsOn`](/repo/docs/reference/configuration#dependson) to easily configure this.
```json title="./turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["^build"]
}
}
}
```
Now, we can run `turbo run build`, and it'll automatically build our packages *before* it builds our app.
### Setting up a dev script
There's a small issue with our setup. We are building our package just fine, but it's not working great in dev. Changes that we make to our `@repo/math` package aren't being reflected in our app.
That's because we don't have a `dev` script to rebuild our packages while we're working. We can add one easily:
```json title="./packages/math/package.json"
// [!code word:--watch]
{
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts",
"dev": "tsup src/index.ts --format cjs,esm --dts --watch"
}
}
```
This passes the `--watch` flag to `tsup`, meaning it will watch for file changes.
If we've already set up [dev scripts](/repo/docs/crafting-your-repository/developing-applications#configuring-development-tasks) in our `turbo.json`, running `turbo run dev` will run our `packages/math` dev task in parallel with our `apps/web` dev task.
Our package is now in a spot where we can consider deploying to npm. In our [versioning and publishing](#versioning-and-publishing) section, we'll do just that.
## Versioning and publishing
Manually versioning and publishing packages in a monorepo can be tiresome. Luckily, there's a tool that makes things easy - the [Changesets](https://github.com/changesets/changesets) CLI.
We recommend Changesets because it's intuitive to use, and - just like Turborepo - fits with the monorepo tools you're already used to.
Some alternatives are:
* [intuit/auto](https://github.com/intuit/auto) - Generate releases based on semantic version labels on pull requests
* [microsoft/beachball](https://github.com/microsoft/beachball) - The Sunniest Semantic Version Bumper
## Publishing
Once your package has been bundled, you can then publish it to the npm registry.
We recommend taking a look at the Changesets docs. Here's our recommended reading order:
1. [Why use changesets?](https://github.com/changesets/changesets/blob/main/docs/intro-to-using-changesets.md) - an intro that takes you through the fundamentals.
2. [Installation instructions](https://github.com/changesets/changesets/blob/main/packages/cli/README.md)
3. If you're using GitHub, consider using the [Changeset GitHub bot](https://github.com/apps/changeset-bot) - a bot to nudge you to add changesets to PR's.
4. You should also consider adding the [Changesets GitHub action](https://github.com/changesets/action) - a tool which makes publishing extremely easy.
## Using Changesets with Turborepo
Once you've started using Changesets, you'll gain access to three useful commands:
```bash title="Terminal"
# Add a new changeset
changeset
# Create new versions of packages
changeset version
# Publish all changed packages to npm
changeset publish
```
Linking your publishing flow into Turborepo can make organizing your deploy a lot simpler and faster.
Our recommendation is to configure Changesets to automatically commit `changeset version`'s changes
```json title="./.changeset/config.json"
{
// …
"commit": true,
// …
}
```
and add a `publish-packages` script into your root `package.json`:
```json title="./package.json"
{
"scripts": {
// Include build, lint, test - all the things you need to run
// before publishing
"publish-packages": "turbo run build lint test && changeset version && changeset publish"
}
}
```
If your packages are public, set Changeset's `access` to `public`:
```json title="./.changeset/config.json"
{
// …
"access": "public",
// …
}
```
We recommend `publish-packages` so that it doesn't conflict with npm's
built-in `publish` script.
This means that when you run `publish-packages`, your monorepo gets built, linted, tested and published - and you benefit from all of Turborepo's speedups.
file: ./content/repo-docs/guides/single-package-workspaces.mdx
meta: {
"title": "Single-package workspaces",
"description": "Learn how to use Turborepo in a single-package workspace."
}
import { Callout } from '#/components/callout';
import { PackageManagerTabs, Tab } from '#/components/tabs';
While Turborepo is highly effective in [multi-package workspaces](https://vercel.com/docs/vercel-platform/glossary#multi-package-workspace) (commonly referred to as monorepos), it can also be used to make [single-package workspaces](https://vercel.com/docs/vercel-platform/glossary#single-package-workspace) faster.
Turborepo's most important features work in single-package workspaces including local and [Remote Caching](/repo/docs/core-concepts/remote-caching) and task parallelization. Features that don't work are ones that don't make sense in the context of a single package, like package tasks (`app#build`).
Examples of single-package workspaces are the output of `npx create-next-app`
or `npm create vite`.
## Installation
Install `turbo` into your application:
```bash title="Terminal"
npm install turbo --save-dev
```
```bash title="Terminal"
yarn add turbo --dev
```
```bash title="Terminal"
pnpm install turbo --save-dev
```
### Running a `package.json` script using global `turbo` (optional)
For even faster developer workflows, you can [install `turbo` globally](/repo/docs/getting-started/installation#global-installation), too, and run commands directly from the command line.
Once installed, you can run `turbo build` and Turborepo will run your `build` script from `package.json`. Running `turbo build` again will hit the cache.
At this point, `turbo` isn't providing much value since you're likely to only be rebuilding your application when code changes and, when your code changes, `turbo` will miss the cache. In two short steps, you can get more out of `turbo`.
## Running many scripts with one command
In many repositories, there are setup tasks or pre-build steps to run. These tasks are often run one at a time - but you can easily turn them into one script with `turbo`.
For example, let's say you have a project where we always have to set up a development environment whenever you start working. You need to:
1. Start a Docker container for a database.
2. Push a database schema to the database.
3. Seed the database with data.
4. Start the development server.
You can schedule these tasks into one command using Turborepo. First, create scripts in your `package.json`:
```json title="package.json"
{
"name": "@acme/my-app",
"version": "0.0.0",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"check-types": "tsc --noEmit",
"db:up": "docker-compose up -d",
"db:push": "your-orm-tool schema-push",
"db:seed": "node ./db-seed.js"
}
}
```
Then, create tasks in `turbo.json` to run these scripts in order:
```json title="./turbo.json"
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"dev": {
"dependsOn": ["db:seed"],
"cache": false,
"persistent": true
},
"db:seed": {
"dependsOn": ["db:push"],
"cache": false
},
"db:push": {
"dependsOn": ["db:up"],
"cache": false
},
"db:up": {
"cache": false
}
}
}
```
The `dependsOn` arrays in the tasks above create a sequential order for the tasks. When you run `turbo dev`, the scripts for `db:up`, then `db:push`, then `db:seed` will be ran first.
## Parallelizing tasks
Using `turbo` to parallelize tasks results in speeding up tasks by running all at once, when they can be. For instance, you can run your ESLint, TypeScript, and Prettier checks at the same time. Given scripts like:
```json title="./package.json"
{
"scripts": {
"lint": "eslint .",
"format": "prettier .",
"check-types": "tsc --noEmit"
}
}
```
You can create a configuration like this one:
```json title="turbo.json"
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"lint": {},
"format": {},
"check-types": {}
}
}
```
Then, to run all tasks at the same time:
```bash title="Terminal"
turbo check-types lint format
```
## Optimizing task using inputs
Because Turborepo will treat a single-package workspace as one package, it can help to optimize inputs to tasks to make sure unrelated changes don't create cache misses.
For instance, a script for checking types using `tsc --noEmit` can be configured with inputs that only include TypeScript files:
```json title="./turbo.json"
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"check-types": {
"inputs": ["**/*.{ts,tsx}"]
}
}
}
```
file: ./content/repo-docs/guides/skipping-tasks.mdx
meta: {
"title": "Skipping tasks",
"description": "Never do the same work twice."
}
import { Callout } from '#/components/callout';
[Caching](/repo/docs/crafting-your-repository/caching) dramatically speeds up your tasks - but you may be able to go even faster by using `npx turbo-ignore`. If a workspace is unaffected by your code changes, you can completely skip executing a task altogether.
Let's say you want to skip the unit tests for your `web` workspace when there aren't any changes to your `web` application (or its package dependencies). If you are already using [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching), you will probably get a cache hit - but you would still spend time provisioning the CI container, installing `npm` dependencies, and other things that can take a while.
Ideally, you would do a quick check to see if any of that work needs to happen in the first place.
***
After you've checked out the repo, but **before** any other work, you can take a few seconds to check that your `web` tests have changed since the parent commit.
```bash title="Terminal"
npx turbo-ignore web --task=test
```
This command will:
1. Filter for the `web` workspace.
2. Create the `dry` output for your `test` task compared to your parent commit.
3. Parse the output to determine which packages have changed.
4. Exit with a `1` code if changes are detected. Otherwise, exits with a `0`.
While you may have been able to hit a `>>> FULL TURBO` cache for this task, you just saved time with all of the other setup tasks required to run your CI.
## Using `turbo-ignore`
To skip unaffected work, first ensure that your Git history is available on the machine. Then, run `npx turbo-ignore`.
`turbo-ignore` uses a combination of the `--filter` and `--dry=json` flags to find changes from the parent commit to the current commit to identify affected packages. By default, `turbo-ignore` finds the difference for the **build task in the current working directory**, but you can [customize this behavior with flags](#customizing-behavior).
Here's an example of the command that will be built and run:
```bash title="Terminal"
npx turbo run build --filter=@example/web...3c8387ffd98b751305fe3f0284befdd00cbd4610 --dry=json
```
Note that a dry run does not *execute* the build task. Instead, it checks your packages to see if your code changes will affect your build (or other task) in only a few seconds.
If `turbo-ignore` finds that the task can be skipped, it will exit the process with a `0` code. If changes have been found, the process will exit with `1`.
On Vercel, the previously deployed SHA will be used instead of the parent
commit.
## Customizing behavior
To specify a workspace, you can add it to your command like:
```bash title="Terminal"
npx turbo-ignore web
```
where `web` is your workspace's name running the default `build` task.
If you'd like to change the task, use the `--task` flag to specify the task for the command that `turbo-ignore` will invoke.
## Using `turbo-ignore` on Vercel
To use `npx turbo-ignore` on Vercel, you can use the [Ignored Build Step](https://vercel.com/docs/concepts/projects/overview#ignored-build-step) feature. Vercel will automatically infer the correct arguments to successfully run `turbo-ignore`.
## Customizing behavior
When not on Vercel, specify a commit for comparison using the `--fallback` flag.
On Vercel, you can specify the `--fallback` flag to give Vercel a git ref to compare against when the default comparison is not available. By default, Vercel compares to the most recently deployed SHA so this is useful for use cases like avoiding a deploy for the first commit to a branch.
file: ./content/repo-docs/messages/invalid-env-prefix.mdx
meta: {
"title": "Invalid environment variable prefix",
"description": "Learn more about errors with invalid environment variable prefixes in Turborepo."
}
## Why this error occurred
When declaring environment variables in your `turbo.json`, you cannot prefix them with `$`. This
was an old syntax for declaring a dependency on an environment variable that was deprecated in Turbo 1.5.
```json title="./turbo.json"
{
"globalEnv": ["$MY_ENV_VAR"]
}
```
The environment variable declared above has the `$` prefix.
## Solution
Remove the `$` prefix from your environment variable declaration.
```json title="./turbo.json"
{
"globalEnv": ["MY_ENV_VAR"]
}
```
You can migrate to the `env` and `globalEnv` keys using `npx @turbo/codemod migrate-env-var-dependencies`.
Check out [the codemod's documentation for more details](/repo/docs/reference/turbo-codemod#turborepo-1x).
file: ./content/repo-docs/messages/missing-root-task-in-turbo-json.mdx
meta: {
"title": "Missing root task in turbo.json",
"description": "Learn more about errors for missing root tasks in turbo.json in Turborepo."
}
## Why this error occurred
Root tasks are the scripts defined in the monorepo's root `package.json`. These tasks often call `turbo`. For example:
```json title="./package.json"
{
"scripts": {
"build": "turbo run build"
}
}
```
This creates a problem when we declare [topological dependencies](/repo/docs/reference/configuration#dependson). Topological
dependencies specify that your package's dependencies should execute their tasks before your package executes its own task.
```json title="./turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["^build"]
}
}
}
```
Because the root package is a dependency for all packages inside your workspace, its task would get executed first.
But since its task calls `turbo`, this would cause an infinite loop.
## Solution
As long as the root task does *not* call `turbo`, you can add it to the `tasks` field in `turbo.json`:
```json title="./turbo.json"
{
"tasks": {
"//#build": {}
}
}
```
This will permit tasks to depend on `//#build`.
However, if the root task does call `turbo`, this can cause infinite recursion. In this case, we don't recommend depending
on the root task. Instead, you can determine the tasks that this root task depends on, and depend on those directly.
For instance, if `//#build` depends on `app#lint` and `docs#lint`, then you can declare those as dependencies.
file: ./content/repo-docs/messages/package-task-in-single-package-workspace.mdx
meta: {
"title": "Package task in single-package workspace error",
"description": "Learn more about errors with package tasks in single-package workspaces."
}
## Why this error occurred
In single package mode, there cannot be multiple packages in your repository. Therefore, declaring a task in the
`turbo.json` with a specified package name is not permitted.
```json title="./turbo.json"
{
"tasks": {
"app#build": {
"cache": true
}
}
}
```
## Solution
Remove the package name from the task declaration.
```json title="./turbo.json"
{
"tasks": {
"build": {
"cache": true
}
}
}
```
Alternatively, if you would like to have multiple packages, you can [specify the workspaces in your repository](/repo/docs/getting-started/add-to-existing-repository).
file: ./content/repo-docs/messages/recursive-turbo-invocations.mdx
meta: {
"title": "Recursive `turbo` invocations",
"description": "Learn more about errors with recursive sccripts and tasks in Turborepo."
}
## Why this error occurred
When a cycle of `turbo` invocations is detected in a [single-package workspace](https://turbo.build/repo/docs/guides/single-package-workspaces), Turborepo will error to prevent the recursive calls to itself. Typically, this situation occurs for one of two reasons:
### Recursion in scripts and tasks
In a single-package workspace, a script in `package.json` that calls a Turborepo task with the same name causes a loop.
```json title="./package.json"
{
"scripts": {
"build": "turbo run build"
}
}
```
Calling the `build` script calls `turbo run build`. `turbo run build` then calls the `build` script, initiating the loop of recursive calls.
To resolve this, ensure that the name of the script in `package.json` is not the same as the Turborepo task. For example, to fix the snippet above, renaming the script would break the cycle:
```json title="./package.json"
{
"scripts": {
"build:app": "turbo run build"
}
}
```
### Package manager Workspace misconfiguration
A misconfigured workspace can make it appear that a [multi-package workspace](https://vercel.com/docs/vercel-platform/glossary#multi-package-workspace) is a single-package workspace. This causes Turborepo to infer that the repository is of the wrong type, causing it to see the script in `package.json` to be recursive.
Your repo can end up in this state in a few ways, with the most common being that the [packages are not defined according to your package manager](https://turbo.build/repo/docs/crafting-your-repository/structuring-a-repository#specifying-packages-in-a-monorepo). An npm workspace that is missing the `workspaces` field in `package.json` or a pnpm workspace that is missing a `pnpm-workspace.yaml` file can result in this error message.
Check that your repository is complying with standards for multi-package workspaces and correct any issues.
file: ./content/repo-docs/messages/unnecessary-package-task-syntax.mdx
meta: {
"title": "Unnecessary package task syntax error",
"description": "Learn more about errors with unnecessary package task syntax in Turborepo."
}
## Why this error occurred
Turborepo supports adding additional `turbo.json` files in a package directory
to override the `turbo.json` file declared at the repository root, a feature called [Workspace Configurations](/repo/docs/crafting-your-repository/structuring-a-repository#specifying-packages-in-a-monorepo).
In those additional `turbo.json` files, you can only configure tasks for that specific
package. Therefore, only the task name should be included in the task,
not the package and task name (`package#task`).
`turbo.json` file in `apps/web` directory:
```json title="./turbo.json"
{
"tasks": {
"web#build": {
"dependsOn": ["lint"]
}
}
}
```
Since this `turbo.json` file is inside a package directory, the `web` prefix is unnecessary.
## Solution
Remove the package prefix from the task name:
```json title="./turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["lint"]
}
}
}
```
file: ./content/repo-docs/reference/bin.mdx
meta: {
"title": "bin",
"description": "API reference for the `turbo bin` command"
}
Get the path to the `turbo` binary.
When using [**global `turbo`**](/repo/docs/getting-started/installation#global-installation), this will be the path to the global `turbo` binary. You're likely to see a path to the global directory of the package manager you used to install `turbo`.
When using [**local `turbo`**](/repo/docs/getting-started/installation#repository-installation), this will be the path to the local `turbo` binary. When `turbo` is installed in your repository, it is likely to be a path to `node_modules`.
file: ./content/repo-docs/reference/boundaries.mdx
meta: {
"title": "boundaries",
"description": "API reference for the `turbo boundaries` command"
}
import { ExperimentalBadge } from '#/components/experimental-badge';
import { Callout } from '#/components/callout';
Experimental
Boundaries ensure that Turborepo features work correctly by checking for package manager Workspace violations.
```bash title="Terminal"
turbo boundaries
```
This feature is experimental, and we're looking for your feedback on [the
Boundaries RFC](https://github.com/vercel/turborepo/discussions/9435).
This command will notify for two types of violations:
* Importing a file outside of the package's directory
* Importing a package that is not specified as a dependency in the package's `package.json`
## Tags
Boundaries also has a feature that lets you add tags to packages. These tags can be used to create rules
for Boundaries to check. For example, you can add an `internal` tag to your UI package:
```json title="./packages/ui/turbo.json"
{
"tags": ["internal"]
}
```
And then declare a rule that packages with a `public` tag cannot depend on packages with an `internal` tag:
```json title="./turbo.json"
{
"boundaries": {
"tags": {
"public": {
"dependencies": {
"deny": ["internal"]
}
}
}
}
}
```
Alternatively, you may want `public` packages to only depend on other `public` packages:
```json title="turbo.json"
{
"boundaries": {
"tags": {
"public": {
"dependencies": {
"allow": ["public"]
}
}
}
}
}
```
Likewise, you can add restrictions for a tag's dependents, i.e. packages that import packages with the tag.
```json title="turbo.json"
{
"boundaries": {
"tags": {
"private": {
"dependents": {
"deny": ["public"]
}
}
}
}
}
```
Tags allow you to ensure that the wrong package isn't getting imported somewhere in your graph. These rules are
applied even for dependencies of dependencies, so if you import a package that in turn imports another package
with a denied tag, you will still get a rule violation.
file: ./content/repo-docs/reference/configuration.mdx
meta: {
"title": "Configuring turbo.json",
"description": "Learn how to configure Turborepo through `turbo.json`."
}
import { Callout } from '#/components/callout';
import { InVersion } from '#/components/in-version';
import { ExperimentalBadge } from '#/components/experimental-badge';
import Link from 'next/link';
Configure the behavior of `turbo` by adding a `turbo.json` file in your Workspace's root directory.
Changing your root `turbo.json` file will invalidate the cache for all tasks
because it's considered in [the global
hash](/repo/docs/crafting-your-repository/caching#global-hash-inputs). If
you'd like the flexibility to change configuration without impacting the
global hash, use [Package
Configurations](/repo/docs/reference/package-configurations).
## Global options
### `extends`
```jsonc title="./apps/web/turbo.json"
{
"extends": ["//"]
}
```
Extend from the root `turbo.json` to create specific configuration for a package using [Package Configurations](/repo/docs/reference/package-configurations).
* The only valid value for `extends` is `["//"]` to inherit configuration from the root `turbo.json`.
* If `extends` is used in the root `turbo.json`, it will be ignored.
### `globalDependencies`
```jsonc title="./turbo.json"
{
"globalDependencies": [".env", "tsconfig.json"]
}
```
A list of globs that you want to include in all task hashes. **If any file matching these globs changes, all tasks will miss cache.** Globs are relative to the location of `turbo.json`.
By default, all files in source control in the Workspace root are included in the global hash.
Globs must be in the repository's source control root. Globs outside of the
repository aren't supported.
### `globalEnv`
```jsonc title="./turbo.json"
{
"globalEnv": ["GITHUB_TOKEN", "PACKAGE_VERSION", "NODE_ENV"]
}
```
A list of environment variables that you want to impact the hash of all tasks. Any change to these environment variables will cause all tasks to miss cache.
For more on wildcard and negation syntax, [see the `env` section](#env).
### `globalPassThroughEnv`
```jsonc title="./turbo.json"
{
"globalPassThroughEnv": ["AWS_SECRET_KEY", "GITHUB_TOKEN"]
}
```
A list of environment variables that you want to make available to tasks. Using this key opts all tasks into [Strict Environment Variable Mode](/repo/docs/crafting-your-repository/using-environment-variables#strict-mode).
Additionally, Turborepo has a built-in set of global passthrough variables for common cases, like operating system environment variables. This includes variables like `HOME`, `PATH`, `APPDATA`, `SHELL`, `PWD`, and more. The full list can be found [in the source code](https://github.com/vercel/turborepo/blob/main/crates/turborepo-lib/src/task_hash.rs).
If you want changes in these variables to cause cache misses, you will need to
include them in [`env`](#env) or [`globalEnv`](#globalenv).
### `ui`
Default: `"stream"`
Select a terminal UI for the repository.
`"tui"` allows for viewing each log at once and interacting with the task. `"stream"` outputs logs as they come in and is not interactive.
```json title="Terminal"
{
"ui": "tui" | "stream"
}
```
### `dangerouslyDisablePackageManagerCheck`
Default: `false`
Turborepo uses your repository's lockfile to determine caching behavior, [Package Graphs](https://turbo.build/repo/docs/core-concepts/internal-packages), and more. Because of this, we use [the `packageManager` field](https://nodejs.org/api/packages.html#packagemanager) to help you stabilize your Turborepo.
To help with incremental migration or in situations where you can't use the `packageManager` field, you may use `--dangerously-disable-package-manager-check` to opt out of this check and assume the risks of unstable lockfiles producing unpredictable behavior. When disabled, Turborepo will attempt a best-effort discovery of the intended package manager meant for the repository.
```jsonc title="./turbo.json"
{
"dangerouslyDisablePackageManagerCheck": true
}
```
You may also opt out of this check via
[`flag`](/repo/docs/reference/run#--dangerously-disable-package-manager-check)
or the
[`TURBO_DANGEROUSLY_DISABLE_PACKAGE_MANAGER_CHECK`](https://turbo.build/repo/docs/reference/system-environment-variables)
environment variable.
### `cacheDir`
Default: `".turbo/cache"`
Specify the filesystem cache directory.
```jsonc title="./turbo.json"
{
"cacheDir": ".turbo/cache"
}
```
### `daemon`
Default: `true`
Turborepo runs a background process to pre-calculate some expensive operations. This standalone process (daemon) is a performance optimization, and not required for proper functioning of `turbo`.
```jsonc title="./turbo.json"
{
"daemon": true
}
```
When running in a CI environment the daemon is always disabled regardless of
this setting.
### `envMode`
Default: `"strict"`
Turborepo's Environment Modes allow you to control which environment variables are available to a task at runtime:
* `"strict"`: Filter environment variables to only those that are specified in the `env` and `globalEnv` keys in `turbo.json`.
* `"loose"`: Allow all environment variables for the process to be available.
```jsonc title="./turbo.json"
{
"envMode": "strict"
}
```
Read more about [Environment Modes](/repo/docs/crafting-your-repository/using-environment-variables#environment-modes).
### `tags` Experimental
```jsonc title="./apps/web/turbo.json"
{
"tags": ["utils"]
}
```
Adds a tag to a package for use with [Boundaries](/repo/docs/reference/boundaries).
This key only works in [Package Configurations](/repo/docs/reference/package-configurations). Using this key in a root `turbo.json` will result in an error.
## Defining tasks
### `tasks`
Each key in the `tasks` object is the name of a task that can be executed by [`turbo run`](/repo/docs/reference/run). Turborepo will search the packages described in your [Workspace's configuration](/repo/docs/crafting-your-repository/structuring-a-repository#specifying-packages-in-a-monorepo) for scripts in `package.json` with the name of the task.
Using the rest of the configuration described in the task, Turborepo will run the scripts in the described order, caching logs and file outputs in [the `outputs` key](#outputs) when provided.
In the example below, we've defined three tasks under the `tasks` key: `build`, `test`, and `dev`.
```jsonc title="./turbo.json"
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
},
"test": {
"outputs": ["coverage/**"],
"dependsOn": ["build"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
```
## Task options
Using the options available in the tasks you define in `tasks`, you can describe how `turbo` will run your tasks.
### `dependsOn`
A list of tasks that are required to complete before the task begins running.
There are three types of `dependsOn` relationships: [dependency relationships](#dependency-relationships), [same-package relationships](#same-package-relationships), and [arbitrary task relationships](#arbitrary-task-relationships).
#### Dependency relationships
Prefixing a string in `dependsOn` with a `^` tells `turbo` that the task must wait for tasks in the package's dependencies to complete first. For example, in the `turbo.json` below:
```jsonc title="./turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["^build"]
}
}
}
```
`turbo` starts at the "bottom" of the package graph and recursively visits each package until it finds a package with no internal dependencies. It will then run the `build` task at the end of the dependency chain first, working its way back to the "top" until all `build` tasks are completed in order.
#### Same package relationships
Task names without the `^` prefix describe a task that depends on a different task within the same package. For example, in the `turbo.json` below:
```jsonc title="./turbo.json"
{
"tasks": {
"test": {
"dependsOn": ["lint", "build"]
}
}
}
```
The `test` task will only run after the `lint` and `build` tasks have completed **in the same package**.
#### Arbitrary task relationships
Specify a task dependency between specific package tasks.
```json title="./turbo.json"
{
"tasks": {
"web#lint": {
"dependsOn": ["utils#build"]
}
}
}
```
In this `turbo.json`, the `web#lint` task will wait for the `utils#build` task to complete.
### `env`
The list of environment variables a task depends on.
```jsonc title="./turbo.json"
{
"tasks": {
"build": {
"env": ["DATABASE_URL"] // Impacts hash of all build tasks
},
"web#build": {
"env": ["API_SERVICE_KEY"] // Impacts hash of web's build task
}
}
}
```
Turborepo automatically includes environment variables prefixed by common
frameworks through [Framework
Inference](/repo/docs/crafting-your-repository/using-environment-variables#framework-inference).
For example, if your package is a Next.js project, you do not need to specify
any environment variables that [start with
`NEXT_PUBLIC_`](https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser).
#### Wildcards
Turborepo supports wildcards for environment variables so you can easily account for all environment variables with a given prefix. For example, the `turbo.json` below include all environment variables that start with `MY_API_` into the hash:
```json title="./turbo.json"
{
"tasks": {
"build": {
"env": ["MY_API_*"]
}
}
}
```
#### Negation
A leading `!` means that the entire pattern will be negated. For instance, the `turbo.json` below will ignore the `MY_API_URL` variable.
```json title="./turbo.json"
{
"tasks": {
"build": {
"env": ["!MY_API_URL"]
}
}
}
```
#### Examples
| Pattern | Description |
| ---------- | ------------------------------------------------------------------------------ |
| `"*"` | Matches every environment variable. |
| `"!*"` | Excludes every environment variable. |
| `"FOO*"` | Matches `FOO`, `FOOD`, `FOO_FIGHTERS`, etc. |
| `"FOO\*"` | Resolves to `"FOO*"` and matches `FOO`, `FOOD`, and `FOO_FIGHTERS`. |
| `"FOO\\*"` | Matches a single environment variable named `FOO*`. |
| `"!FOO*"` | Excludes all environment variables that start with `FOO`. |
| `"\!FOO"` | Resolves to `"!FOO"`, and excludes a single environment variable named `!FOO`. |
| `"\\!FOO"` | Matches a single environment variable named `!FOO`. |
| `"FOO!"` | Matches a single environment variable named `FOO!`. |
### `passThroughEnv`
An allowlist of environment variables that should be made available to this task's runtime, even when in [Strict Environment Mode](/repo/docs/crafting-your-repository/using-environment-variables#strict-mode).
```jsonc title="./turbo.json"
{
"tasks": {
"build": {
// Values will available within `build` scripts
"passThroughEnv": ["AWS_SECRET_KEY", "GITHUB_TOKEN"]
}
}
}
```
Values provided in `passThroughEnv` do not contribute to the cache key for the
task. If you'd like changes to these variables to cause cache misses, you will
need to include them in [`env`](#env) or [`globalEnv`](#globalenv).
### `outputs`
A list of file glob patterns relative to the package's `package.json` to cache when the task is successfully completed.
```jsonc title="./turbo.json"
{
"tasks": {
"build": {
// Cache all files emitted to the packages's `dist` directory
"outputs": ["dist/**"]
}
}
}
```
Omitting this key or passing an empty array tells `turbo` to cache nothing (except logs, which are always cached when caching is enabled).
### `cache`
Default: `true`
Defines if task outputs should be cached. Setting `cache` to false is useful for long-running development tasks and ensuring that a task always runs when it is in the task's execution graph.
```jsonc title="./turbo.json"
{
"tasks": {
"build": {
"outputs": [".svelte-kit/**", "dist/**"] // File outputs will be cached
},
"dev": {
"cache": false, // No outputs will be cached
"persistent": true
}
}
}
```
### `inputs`
Default: `[]`, all files in the package that are checked into source control
A list of file glob patterns relative to the package's `package.json` to consider when determining if a package has changed. `turbo.json` is **always** considered an input.
Visit the [file glob specification](/repo/docs/reference/globs) for more information on globbing syntax.
```jsonc title="./turbo.json"
{
"tasks": {
"test": {
"inputs": ["src/**/*.ts", "src/**/*.tsx", "test/**/*.ts"]
}
}
}
```
Using the `inputs` key opts you out of `turbo`'s default behavior of
considering `.gitignore`. You must reconstruct the globs from `.gitignore` as
desired or use `$TURBO_DEFAULT$` to build off of the default behavior.
#### `$TURBO_DEFAULT$`
Because specifying an `inputs` key immediately opts out of the default behavior, you may use
the special string `$TURBO_DEFAULT$` within the `inputs` array to restore `turbo`'s default behavior. This allows you to tweak the default behavior for more granularity.
```jsonc title="./turbo.json"
{
"tasks": {
"check-types": {
// Consider all default inputs except the package's README
"inputs": ["$TURBO_DEFAULT$", "!README.md"]
}
}
}
```
### `outputLogs`
Default: `full`
Set output logging verbosity. Can be overridden by the [`--output-logs`](/repo/docs/reference/run#--output-logs-option) CLI option.
| Option | Description |
| ------------- | --------------------------------- |
| `full` | Displays all logs |
| `hash-only` | Only show the hashes of the tasks |
| `new-only` | Only show logs from cache misses |
| `errors-only` | Only show logs from task failures |
| `none` | Hides all task logs |
```jsonc title="./turbo.json"
{
"tasks": {
"build": {
"outputLogs": "new-only"
}
}
}
```
### `persistent`
Default: `false`
Label a task as `persistent` to prevent other tasks from depending on long-running processes. Persistent tasks are made [interactive](#interactive) by default.
Because a long-running process won't exit, tasks that would depend on it would never run. Once you've labeled the task as persistent, `turbo` will throw an error if other tasks depend on it.
This option is most useful for development servers or other "watch" tasks.
```jsonc title="./turbo.json"
{
"tasks": {
"dev": {
"persistent": true
}
}
}
```
Tasks marked with `persistent` are also `interactive` by default.
### `interactive`
Default: `false` (Defaults to `true` for tasks marked as `persistent`)
Label a task as `interactive` to make it accept inputs from `stdin` in the terminal UI. Must be used with `persistent`.
This option is most useful for scripts that can be manipulated while they are running, like Jest or Vitest.
```jsonc title="./turbo.json"
{
"tasks": {
"test:watch": {
"interactive": true,
"persistent": true
}
}
}
```
### `interruptible`
Default: `false`
Label a `persistent` task as `interruptible` to allow it to be restarted by `turbo watch`.
`turbo watch` watches for changes to your packages and automatically restarts tasks
that are affected. However, if a task is persistent, it will not be restarted by default.
To enable restarting persistent tasks, set `interruptible` to `true`.
## Boundaries
The `boundaries` tag allows you to define rules for the [`boundaries` command](/repo/docs/reference/boundaries).
```jsonc title="./turbo.json"
{
"boundaries": {}
}
```
### `tags`
Each key in the `tags` object is the name of a tag that can be checked with [`turbo boundaries`](/repo/docs/reference/boundaries).
In the configuration object for a tag, you can define rules for dependencies and dependents.
#### `dependencies` and `dependents`
Rules for a tag's dependencies and dependents.
You can add an allowlist and a denylist:
```jsonc title="./turbo.json"
{
"boundaries": {
"utils": {
"dependencies": {
// permit only packages with the `ui` tag
"allow": ["ui"],
// and ban packages with the `unsafe` tag
"deny": ["unsafe"]
}
}
}
}
```
Both the allowlist and the denylist can be omitted.
```jsonc title="./turbo.json"
{
"boundaries": {
"utils": {
"dependencies": {
// only packages with the `unsafe` tag are banned, all other packages permitted
"deny": ["unsafe"]
}
}
}
}
```
Rules can also be added for a tag's dependents, i.e. packages that import this tag.
```jsonc title="./turbo.json"
{
"boundaries": {
"utils": {
"dependents": {
// only packages with the `web` tag can import packages with the `utils` tag
"allow": ["web"]
}
}
}
}
```
## Remote caching
The global `remoteCache` option has a variety of fields for configuring remote cache usage
```jsonc title="./turbo.json"
{
"remoteCache": {}
}
```
### `enabled`
Default: `true`
Enables remote caching.
When `false`, Turborepo will disable all remote cache operations, even if the repo has a valid token.
If true, remote caching is enabled, but still requires the user to login and link their repo to a remote cache.
### `signature`
Default: `false`
Enables signature verification for requests to the remote cache.
When `true`, Turborepo will sign every uploaded artifact using the value of the environment variable `TURBO_REMOTE_CACHE_SIGNATURE_KEY`.
Turborepo will reject any downloaded artifacts that have an invalid signature or are missing a signature.
### `preflight`
Default: `false`
When enabled, any HTTP request will be preceded by an OPTIONS request to determine if the request is supported by the endpoint.
### `timeout`
Default: `30`
Sets a timeout for remote cache operations.
Value is given in seconds and only whole values are accepted.
If `0` is passed, then there is no timeout for any cache operations.
### `uploadTimeout`
Default: `60`
Sets a timeout for remote cache uploads.
Value is given in seconds and only whole values are accepted.
If `0` is passed, then there is no timeout for any remote cache uploads.
### `apiUrl`
Default: `"https://vercel.com"`
Set endpoint for API calls to the remote cache.
### `loginUrl`
Default: `"https://vercel.com"`
Set endpoint for requesting tokens during `turbo login`.
### `teamId`
The ID of the Remote Cache team.
Value will be passed as `teamId` in the querystring for all Remote Cache HTTP calls.
Must start with `team_` or it will not be used.
### `teamSlug`
The slug of the Remote Cache team.
Value will be passed as `slug` in the querystring for all Remote Cache HTTP calls.
file: ./content/repo-docs/reference/create-turbo.mdx
meta: {
"title": "create-turbo",
"description": "Quickly set up a new Turborepo repository from scratch."
}
import { PackageManagerTabs, Tab } from '#/components/tabs';
import { ExamplesTable } from '#/components/examples-table';
The easiest way to get started with Turborepo is by using `create-turbo`. Use this CLI tool to quickly start building a new monorepo, with everything set up for you.
```bash title="Terminal"
npx create-turbo@latest
```
```bash title="Terminal"
yarn dlx create-turbo@latest
```
```bash title="Terminal"
pnpm dlx create-turbo@latest
```
## Start with an example
The community curates a set of examples to showcase ways to use common tools and libraries with Turborepo. To bootstrap your monorepo with one of the examples, use the `--example` flag:
```bash title="Terminal"
npx create-turbo@latest --example [example-name]
```
```bash title="Terminal"
yarn dlx create-turbo@latest --example [example-name]
```
```bash title="Terminal"
pnpm dlx create-turbo@latest --example [example-name]
```
Use any of the example's names below:
### Use a community example
You can also use a custom starter or example by using a GitHub URL. This is useful for using your own custom starters or examples from the community.
```bash title="Terminal"
npx create-turbo@latest --example [github-url]
```
```bash title="Terminal"
yarn dlx create-turbo@latest --example [github-url]
```
```bash title="Terminal"
pnpm dlx create-turbo@latest --example [github-url]
```
## Options
```txt title="Terminal"
-m, --package-manager to use (choices: "npm", "yarn", "pnpm", "bun")
--skip-install: Do not run a package manager install after creating the project (Default: false)
--skip-transforms: Do not run any code transformation after creating the project (Default: false)
--turbo-version : Use a specific version of turbo (default: latest)
-e, --example [name]|[github-url]: An example to bootstrap the app with. You can use an example name from the official Turborepo repo or a GitHub URL. The URL can use any branch and/or subdirectory
-p, --example-path : In a rare case, your GitHub URL might contain a branch name with a slash (e.g. bug/fix-1) and the path to the example (e.g. foo/bar). In this case, you must specify the path to the example separately: --example-path foo/bar
-v, --version: Output the current version
-h, --help: Display help for command
```
file: ./content/repo-docs/reference/eslint-config-turbo.mdx
meta: {
"title": "eslint-config-turbo",
"description": "Learn more about eslint-config-turbo."
}
import { PackageManagerTabs, Tab } from '#/components/tabs';
[The `eslint-config-turbo` package](https://www.npmjs.com/package/eslint-config-turbo) helps you find environment variables that are used in your code that are not a part of Turborepo's hashing. Environment variables used in your source code that are not accounted for in `turbo.json` will be highlighted in your editor and errors will show as ESLint output.
## Installation
Install `eslint-config-turbo` into the location where your ESLint configuration is held:
```bash title="Terminal"
npm i --save-dev eslint-config-turbo -w @acme/eslint-config
```
```bash title="Terminal"
yarn workspace @acme/eslint-config add eslint-config-turbo --dev
```
```bash title="Terminal"
pnpm add eslint-config-turbo --filter=@repo/eslint-config
```
## Usage (Flat Config `eslint.config.js`)
```js title="./packages/eslint-config/base.js"
import turboConfig from 'eslint-config-turbo/flat';
export default [
...turboConfig,
// Other configuration
];
```
You can also configure rules available in the configuration:
```js title="./packages/eslint-config/base.js"
import turboConfig from 'eslint-config-turbo/flat';
export default [
...turboConfig,
// Other configuration
{
rules: {
'turbo/no-undeclared-env-vars': [
'error',
{
allowList: ['^ENV_[A-Z]+$'],
},
],
},
},
];
```
## Usage (Legacy `eslintrc*`)
Add `turbo` to the extends section of your eslint configuration file. You can omit the `eslint-config-` prefix:
```json title="./packages/eslint-config/base.json"
{
"extends": ["turbo"]
}
```
You can also configure rules available in the configuration:
```json title="./packages/eslint-config/base.json"
{
"plugins": ["turbo"],
"rules": {
"turbo/no-undeclared-env-vars": [
"error",
{
"allowList": ["^ENV_[A-Z]+$"]
}
]
}
}
```
file: ./content/repo-docs/reference/eslint-plugin-turbo.mdx
meta: {
"title": "eslint-plugin-turbo",
"description": "Learn more about eslint-plugin-turbo."
}
import { PackageManagerTabs, Tab } from '#/components/tabs';
[The `eslint-plugin-turbo` package](https://www.npmjs.com/package/eslint-plugin-turbo) helps you find environment variables that are used in your code that are not a part of Turborepo's hashing. Environment variables used in your source code that are not accounted for in `turbo.json` will be highlighted in your editor and errors will show as ESLint output.
## Installation
Install `eslint-config-turbo` into the location where your ESLint configuration is held:
```bash title="Terminal"
npm i --save-dev eslint-config-turbo -w @acme/eslint-config
```
```bash title="Terminal"
yarn workspace @acme/eslint-config add eslint-config-turbo --dev
```
```bash title="Terminal"
pnpm add eslint-config-turbo --filter=@repo/eslint-config
```
## Usage (Flat Config `eslint.config.js`)
ESLint v9 uses the Flat Config format seen below:
```js title="./packages/eslint-config/base.js"
import turbo from 'eslint-plugin-turbo';
export default [turbo.configs['flat/recommended']];
```
Otherwise, you may configure the rules you want to use under the rules section.
```js title="./packages/eslint-config/base.js"
import turbo from 'eslint-plugin-turbo';
export default [
{
plugins: {
turbo,
},
rules: {
'turbo/no-undeclared-env-vars': 'error',
},
},
];
```
## Example (Flat Config `eslint.config.js`)
```js title="./packages/eslint-config/base.js"
import turbo from 'eslint-plugin-turbo';
export default [
{
plugins: {
turbo,
},
rules: {
'turbo/no-undeclared-env-vars': [
'error',
{
allowList: ['^ENV_[A-Z]+$'],
},
],
},
},
];
```
## Usage (Legacy `eslintrc*`)
Add `turbo` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix:
```json title="./packages/eslint-config/base.json"
{
"plugins": ["turbo"]
}
```
Then configure the rules you want to use under the rules section.
```json title="./packages/eslint-config/base.json"
{
"rules": {
"turbo/no-undeclared-env-vars": "error"
}
}
```
## Example (Legacy `eslintrc*`)
```json title="./packages/eslint-config/base.json"
{
"plugins": ["turbo"],
"rules": {
"turbo/no-undeclared-env-vars": [
"error",
{
"allowList": ["^ENV_[A-Z]+$"]
}
]
}
}
```
file: ./content/repo-docs/reference/generate.mdx
meta: {
"title": "generate",
"description": "API reference for the `turbo generate` command"
}
import { Callout } from '#/components/callout';
Extend your Turborepo with new apps and packages.
```bash title="Terminal"
turbo generate
```
* [`turbo generate run [generator-name]`](#run-generator-name): Run custom generators defined in your repository.
* [`turbo generate workspace [options]`](#workspace): Create a new package in your repository by copying an existing one or from the start.
For more information and practical use cases for writing custom generators, visit [the "Generating code" guide](/repo/docs/guides/generating-code).
`turbo gen` is an alias for `turbo generate`. Additionally, `run` is the
default command so `turbo gen` is equivalent to `turbo generate run`.
## `run [generator-name]`
Run custom generators defined in your repository.
```bash title="Terminal"
turbo gen run [generator-name]
```
### Flag options
#### `--args`
Answers to pass directly to the generator's prompts.
#### `--config `
Generator configuration file.
Default: `turbo/generators/config.js`
#### `--root `
The root of your repository
Default: directory with root `turbo.json`
## `workspace`
Create a new workspace.
```bash title="Terminal"
turbo gen workspace [options]
```
### Flag options
#### `--name `
The name for the new workspace to be used in the `package.json` `name` key. The `name` key is the unique identifier for the package in your repository.
#### `--empty`
Creates an empty workspace. Defaults to `true`.
#### `--copy /`
Name of local workspace within your monorepo or a fully qualified GitHub URL with any branch and/or subdirectory.
#### `--destination `
Where the new workspace should be created.
#### `--type `
The type of workspace to create (`app` or `package`).
#### `--root `
The root of your repository. Defaults to the directory of the root `turbo.json`.
#### `--show-all-dependencies`
Prevent filtering dependencies by workspace type when selecting dependencies to add.
#### `--example-path `, `-p `
In a rare case, your GitHub URL might contain a branch name with a slash (e.g. `bug/fix-1`) and the path to the example (e.g. `foo/bar`). In this case, you must specify the path to the example separately.
file: ./content/repo-docs/reference/globs.mdx
meta: {
"title": "File glob specification",
"description": "Learn about the file glob specification used by `turbo`."
}
File globs are used throughout Turborepo for configuring which files to include or exclude in various contexts, allowing you to specifically define the files you want `turbo` to use.
## Glob patterns
| Pattern | Description |
| ----------- | ---------------------------------------------------------------------------------------------------- |
| `*` | Match all files in the directory |
| `**` | Recursively match all files and sub-directories |
| `some-dir/` | Match the `some-dir` directory and its contents |
| `some-dir` | Match a file named `some-dir` or a `some-dir` directory and its contents |
| `some-dir*` | Match files and directories that start with `some-dir`, including contents when matching a directory |
| `*.js` | Match all `.js` files in the directory |
| `!` | Negate the whole glob (automatically applies `/**` to the end of the defined glob) |
## Examples
| Pattern | Description |
| ------------------ | ------------------------------------------------------------------------------------------------- |
| `dist/**` | Match all files in the `dist` directory, its contents, and all sub-directories |
| `dist/` | Match the `dist` directory and its contents |
| `dist` | Match a file named `dist` or a `dist` directory, its contents, and all sub-directories |
| `dist/some-dir/**` | Match all files in the `dist/some-dir` directory and all sub-directories in the current directory |
| `!dist` | Ignore the `dist` directory and all of its contents |
| `dist*` | Match files and directories that start with `dist` |
| `dist/*.js` | Match all `.js` files in the `dist` directory |
| `!dist/*.js` | Ignore all `.js` files in the `dist` directory |
| `dist/**/*.js` | Recursively match all `.js` files in the `dist` directory and its sub-directories |
| `../scripts/**` | Up one directory, match all files and sub-directories in the `scripts` directory |
file: ./content/repo-docs/reference/index.mdx
meta: {
"title": "Turborepo API reference",
"description": "Learn about Turborepo's APIs using the reference."
}
import { Card, Cards } from '#/components/card';
Turborepo's API reference is broken up into the following sections:
## Configuration
## Commands
## Packages
## Flag syntax
Options that require a value can be passed with an equals sign, using quotes when spaces are needed.
```bash title="Terminal"
--opt=value
--opt="value with a space"
--opt value
--opt "value with a space"
```
## Global flags
### `--color`
Forces the use of color, even in non-interactive terminals. This is useful for enabling color output in CI environments like GitHub Actions that have support for rendering color.
### `--no-color`
Suppresses color in terminal output, even in interactive terminals.
### `--no-update-notifier`
Disables the update notification. This notification will be automatically disabled when running in CI environments, but can also be disabled manually via this flag.
Alternatively, you can disable the notification using [the `TURBO_NO_UPDATE_NOTIFIER` environment variable](/repo/docs/reference/system-environment-variables).
file: ./content/repo-docs/reference/info.mdx
meta: {
"title": "info",
"description": "API reference for the `turbo info` command"
}
Print debugging information about your Turborepo.
```bash title="Terminal"
turbo info
```
Example output:
```txt title="Terminal"
CLI:
Version: 2.3.0
Path to executable: /path/to/turbo
Daemon status: Running
Package manager: pnpm
Platform:
Architecture: aarch64
Operating system: macos
Available memory (MB): 12810
Available CPU cores: 10
Environment:
CI: None
Terminal (TERM): xterm-256color
Terminal program (TERM_PROGRAM): tmux
Terminal program version (TERM_PROGRAM_VERSION): 3.4
Shell (SHELL): /bin/zsh
stdin: false
```
file: ./content/repo-docs/reference/link.mdx
meta: {
"title": "link",
"description": "API reference for the `turbo link` command"
}
Link the repository to a Remote Cache provider.
The selected owner (either a user or an organization) will be able to share [cache artifacts](/repo/docs/core-concepts/remote-caching) through [Remote Caching](/repo/docs/core-concepts/remote-caching).
## Flag options
### `--api `
Specifies the URL of your Remote Cache provider.
```bash title="Terminal"
turbo link --api=https://example.com
```
### `--yes`
Answer yes to all prompts
```bash title="Terminal"
turbo link --yes
```
### `--scope `
The scope to which you are linking. For example, when using Vercel, this is your Vercel team's slug.
```bash title="Terminal"
turbo link --scope=your-team
```
file: ./content/repo-docs/reference/login.mdx
meta: {
"title": "login",
"description": "API reference for the `turbo login` command"
}
Log in to your Remote Cache provider.
The default provider is [Vercel](https://vercel.com/). To specify a different provider, use the `--api` option.
## Flag options
### --api \
Set the API URL of the Remote Cache provider.
```bash title="Terminal"
turbo login --api=https://acme.com/api
```
### --login \
Set the URL for login requests that should dynamically generate tokens.
```bash title="Terminal"
turbo login --login=https://acme.com
```
### --sso-team \
Connect to an SSO-enabled team by providing your team slug.
```bash title="Terminal"
turbo login --sso-team=slug-for-team
```
### --manual
Manually enter token instead of requesting one from a login service.
file: ./content/repo-docs/reference/logout.mdx
meta: {
"title": "logout",
"description": "API reference for the `turbo logout` command"
}
Log out of the account associated with your Remote Cache provider.
file: ./content/repo-docs/reference/ls.mdx
meta: {
"title": "ls",
"description": "API reference for the `turbo ls` command"
}
import { ExperimentalBadge } from '#/components/experimental-badge';
List packages in your monorepo.
```bash title="Terminal"
turbo ls [package(s)] [flags]
```
When scoped to the entire repository, output includes package manager, package count, and all package names and directories.
```bash title="Terminal"
# List all packages in the repository
turbo ls
```
When scoped to one or more packages, output includes package name, directory, internal dependencies, and all tasks.
```bash title="Terminal"
# List only two packages
turbo ls web @repo/ui [package(s)]
```
## Flags
### `--affected`
Automatically filter to only packages that are affected by changes on the current branch.
By default the changes considered are those between `main` and `HEAD`.
* You can override `main` as the default base by setting `TURBO_SCM_BASE`.
* You can override `HEAD` as the default head by setting `TURBO_SCM_HEAD`.
```bash title="Terminal"
TURBO_SCM_BASE=development turbo ls --affected
```
### `--output `
Format to output the results. `json` or `pretty` (default)
```bash title="Terminal"
turbo ls --output=json
```
file: ./content/repo-docs/reference/options-overview.mdx
meta: {
"title": "Options overview",
"description": "Flags, configurations, and System Environment Variables for Turborepo"
}
There are three ways to manage the behavior of a `turbo` invocation:
* [Configuration in `turbo.json`](/repo/docs/reference/configuration)
* [System Environment Variables](/repo/docs/reference/system-environment-variables)
* [Flags passed to the CLI invocation](/repo/docs/reference/run)
The three strategies listed above are in order of precedence. Where a flag value is provided, for the same System Environment Variable or `turbo.json` configuration, the value for the flag will be used. Because of this, we recommend using:
* `turbo.json` configuration for defaults
* System Environment Variables for per-environment overrides
* Flags for per-invocation overrides
## Options table
### Caching
file: ./content/repo-docs/reference/package-configurations.mdx
meta: {
"title": "Package Configurations",
"description": "Learn how to use Package Configurations to bring greater task flexibility to your monorepo's package."
}
import { Callout } from '#/components/callout';
import { ExperimentalBadge } from '#/components/experimental-badge';
Many monorepos can declare a `turbo.json` in the root directory with a
[task description](/repo/docs/reference/configuration#tasks) that applies to all packages. But, sometimes, a monorepo can contain packages that need to configure their tasks differently.
To accommodate this, Turborepo enables you to extend the root configuration with a `turbo.json` in any package. This flexibility enables a more diverse set of apps and packages to co-exist in a Workspace, and allows package owners to maintain specialized tasks and configuration without affecting other apps and packages of the monorepo.
## How it works
To override the configuration for any task defined in the root `turbo.json`, add
a `turbo.json` file in any package of your monorepo with a top-level `extends`
key:
```jsonc title="./apps/my-app/turbo.json"
{
"extends": ["//"],
"tasks": {
"build": {
// Custom configuration for the build task in this package
},
"special-task": {} // New task specific to this package
}
}
```
For now, the only valid value for the `extends` key is `["//"]`. `//` is a
special name used to identify the root directory of the monorepo.
Configuration in a package can override any of [the configurations for a
task](/repo/docs/reference/configuration#defining-tasks). Any keys that are not included are inherited
from the extended `turbo.json`.
## Examples
### Different frameworks in one Workspace
Let's say your monorepo has multiple [Next.js](https://nextjs.org) apps, and one [SvelteKit](https://kit.svelte.dev)
app. Both frameworks create their build output with a `build` script in their
respective `package.json`. You *could* configure Turborepo to run these tasks
with a single `turbo.json` at the root like this:
```jsonc title="./turbo.json"
{
"tasks": {
"build": {
"outputs": [".next/**", "!.next/cache/**", ".svelte-kit/**"]
}
}
}
```
Notice that both `.next/**` and `.svelte-kit/**` need to be specified as
[`outputs`](/repo/docs/reference/configuration#outputs), even though Next.js apps do not generate a `.svelte-kit` directory, and
vice versa.
With Package Configurations, you can instead add custom
configuration in the SvelteKit package in `apps/my-svelte-kit-app/turbo.json`:
```jsonc title="./apps/my-svelte-kit-app/turbo.json"
{
"extends": ["//"],
"tasks": {
"build": {
"outputs": [".svelte-kit/**"]
}
}
}
```
and remove the SvelteKit-specific [`outputs`](/repo/docs/reference/configuration#outputs) from the root configuration:
```diff title="./turbo.json"
{
"tasks": {
"build": {
- "outputs": [".next/**", "!.next/cache/**", ".svelte-kit/**"]
+ "outputs": [".next/**", "!.next/cache/**"]
}
}
}
```
This not only makes each configuration easier to read, it puts the configuration
closer to where it is used.
### Specialized tasks
In another example, say that the `build` task in one package `dependsOn` a
`compile` task. You could universally declare it as `dependsOn: ["compile"]`.
This means that your root `turbo.json` has to have an empty `compile` task
entry:
```json title="./turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["compile"]
},
"compile": {}
}
}
```
With Package Configurations, you can move that `compile` task into the
`apps/my-custom-app/turbo.json`,
```json title="./apps/my-app/turbo.json"
{
"extends": ["//"],
"tasks": {
"build": {
"dependsOn": ["compile"]
},
"compile": {}
}
}
```
and remove it from the root:
```diff title="./turbo.json"
{
"tasks": {
+ "build": {}
- "build": {
- "dependsOn": ["compile"]
- },
- "compile": {}
}
}
```
Now, the owners of `my-app`, can have full ownership over their `build` task,
but continue to inherit any other tasks defined at the root.
## Comparison to package-specific tasks
At first glance, Package Configurations may sound a lot like the
[`package#task` syntax](/repo/docs/crafting-your-repository/configuring-tasks#depending-on-a-specific-task-in-a-specific-package) in the root `turbo.json`. The features are
similar, but have one significant difference: when you declare a package-specific task
in the root `turbo.json`, it *completely* overwrites the baseline task
configuration. With a Package Configuration, the task configuration is merged
instead.
Consider the example of the monorepo with multiple Next.js apps and a Sveltekit
app again. With a package-specific task, you might configure your root
`turbo.json` like this:
```jsonc title="./turbo.json"
{
"tasks": {
"build": {
"outputLogs": "hash-only",
"inputs": ["src/**"],
"outputs": [".next/**", "!.next/cache/**"]
},
"my-sveltekit-app#build": {
"outputLogs": "hash-only", // must duplicate this
"inputs": ["src/**"], // must duplicate this
"outputs": [".svelte-kit/**"]
}
}
}
```
In this example, `my-sveltekit-app#build` completely overwrites `build` for the
Sveltekit app, so `outputLogs` and `inputs` also need to be duplicated.
With Package Configurations, `outputLogs` and `inputs` are inherited, so
you don't need to duplicate them. You only need to override `outputs` in
`my-sveltekit-app` config.
Although there are no plans to remove package-specific task configurations, we
expect that Package Configurations can be used for most use cases instead.
## Boundaries Tags Experimental
Package Configurations are also used to declare Tags for Boundaries. To do so, add a `tags` field to your `turbo.json`:
```diff title="./apps/my-app/turbo.json"
{
+ "tags": ["my-tag"],
"extends": ["//"],
"tasks": {
"build": {
"dependsOn": ["compile"]
},
"compile": {}
}
}
```
From there, you can define rules for which dependencies or dependents a tag can have. Check out the [Boundaries documentation](/repo/docs/reference/boundaries#tags) for more details.
## Limitations
Although the general idea is the same as the root `turbo.json`, Package
Configurations come with a set of guardrails that can prevent packages from creating
potentially confusing situations.
### Package Configurations cannot use [the `workspace#task` syntax](/repo/docs/crafting-your-repository/running-tasks) as task entries
The `package` is inferred based on the location of the configuration, and it is
not possible to change configuration for another package. For example, in a
Package Configuration for `my-nextjs-app`:
```jsonc title="./apps/my-nextjs-app/turbo.json"
{
"tasks": {
"my-nextjs-app#build": {
// ❌ This is not allowed. Even though it's
// referencing the correct package, "my-nextjs-app"
// is inferred, and we don't need to specify it again.
// This syntax also has different behavior, so we do not want to allow it.
// (see "Comparison to package-specific tasks" section)
},
"my-sveltekit-app#build": {
// ❌ Changing configuration for the "my-sveltekit-app" package
// from Package Configuration in "my-nextjs-app" is not allowed.
},
"build": {
// ✅ just use the task name!
}
}
}
```
Note that the `build` task can still depend on a package-specific task:
```jsonc title="./apps/my-nextjs-app/turbo.json"
{
"tasks": {
"build": {
"dependsOn": ["some-pkg#compile"] // [!code highlight]
}
}
}
```
### Package Configurations can only override values in the `tasks` key
It is not possible to override [global configuration](/repo/docs/reference/configuration#global-options) like `globalEnv` or `globalDependencies` in a Package Configuration. Configuration that would need to be altered in a Package Configuration is not truly global and should be configured differently.
### Root turbo.json cannot use the `extends` key
To avoid creating circular dependencies on packages, the root `turbo.json`
cannot extend from anything. The `extends` key will be ignored.
## Troubleshooting
In large monorepos, it can sometimes be difficult to understand how Turborepo is
interpreting your configuration. To help, we've added a `resolvedTaskDefinition`
to the [Dry Run](/repo/docs/reference/run#--dry----dry-run) output. If you run `turbo run build --dry-run`, for example, the
output will include the combination of all `turbo.json` configurations that were
considered before running the `build` task.
file: ./content/repo-docs/reference/prune.mdx
meta: {
"title": "prune",
"description": "API reference for the `turbo prune` command"
}
import { File, Folder, Files } from '#/components/files';
Generate a partial monorepo for a target package. The output will be placed into a directory named `out` containing the following:
* The full source code of all internal packages needed to build the target.
* A pruned lockfile containing the subset of the original lockfile needed to build the target.
* A copy of the root `package.json`.
```bash title="Terminal"
turbo prune [package]
```
### Example
Starting with a repository with the following structure:
Run `turbo prune frontend` to generate a pruned workspace for the `frontend` application in an `out` directory:
### Options
#### `--docker`
Defaults to `false`.
Alter the output directory to make it easier to use with [Docker best practices and layer caching](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/). The directory will contain:
* A folder named `json` with the pruned workspace's `package.json` files.
* A folder named `full` with the pruned workspace's full source code for the internal packages needed to build the target.
* A pruned lockfile containing the subset of the original lockfile needed to build the target.
Using the same example from above, running `turbo prune frontend --docker` will generate the following:
#### `--out-dir `
Defaults to `./out`.
Customize the directory the pruned output is generated in.
#### `--use-gitignore[=]`
Default: `true`
Respect `.gitignore` file(s) when copying files to the output directory.
### Comparison to `pnpm deploy`
While both `turbo prune` and [`pnpm deploy`](https://pnpm.io/cli/deploy) are used to isolate packages in a monorepo, they serve different purposes and produce different outputs.
Where `turbo prune` generates a partial monorepo, `pnpm deploy` generates a directory that only contains the contents of the target package.
The `pnpm deploy` generated directory has a self-contained `node_modules` with hard linked internal dependencies.
This results in a portable package that can be directly copied to a server and used without additional steps.
The repository structure is not retained, as the focus is on producing a standalone deployable package.
file: ./content/repo-docs/reference/query.mdx
meta: {
"title": "query",
"description": "API reference for the `turbo query` command"
}
import { ExperimentalBadge } from '#/components/experimental-badge';
Run GraphQL queries against your monorepo.
```bash title="Terminal"
turbo query [query] [flags]
```
When no arguments are passed, the command will open a GraphiQL playground to run queries.
```bash title="Terminal"
turbo query
```
When passed a query string, the command will run the query and output the results.
```bash title="Terminal"
turbo query "query { packages { items { name } } }"
```
When passed a file path, the command will read the file and run the query.
```bash title="Terminal"
turbo query query.gql
```
file: ./content/repo-docs/reference/run.mdx
meta: {
"title": "run",
"description": "API reference for the `turbo run` command"
}
import { Callout } from '#/components/callout';
Run tasks specified in `turbo.json`.
```bash title="Terminal"
turbo run [tasks] [options] [-- [args passed to tasks]]
```
* **\[tasks]**: Turborepo can run one or many tasks at the same time. To run a task through `turbo`, it must be specified in `turbo.json`.
* **\[options]**: Options are used to control the behavior of the `turbo run` command. Available flag options are described below.
* **\[-- \[args passed to tasks]]**: You may also pass arguments to the underlying scripts. Note that all arguments will be passed to all tasks.
`turbo run` is aliased to `turbo`. `turbo run build lint check-types` is the
same as `turbo build lint check-types`. We recommend [using `turbo run` in CI
pipelines](/repo/docs/crafting-your-repository/constructing-ci#use-turbo-run-in-ci)
and `turbo` with [global `turbo`
locally](/repo/docs/getting-started/installation#global-installation) for ease
of use.
If no tasks are provided, `turbo` will display what tasks are available for the packages in the repository.
```bash title="Terminal"
turbo run
```
## Options
### `--affected`
Automatically filter to only packages that are affected by changes on the current branch.
```bash title="Terminal"
turbo run build lint test --affected
```
By default, the flag is equivalent to `--filter=...[main...HEAD]`. This considers changes between `main` and `HEAD` from Git's perspective.
You can override the default base and head with their respective [System Environment Variables](/repo/docs/reference/system-environment-variables).
```bash title="Terminal"
# Override Git comparison base
TURBO_SCM_BASE=development turbo run build --affected
# Override Git comparison head
TURBO_SCM_HEAD=your-branch turbo run build --affected
```
The comparison requires everything between base and head to exist in the
checkout. If the checkout is too shallow, then all packages will be considered
changed.
### `--cache `
Default: `local:rw,remote:rw`
Specify caching sources for the run. Accepts a comma-separated list of options:
* `local`: Use the local filesystem cache
* `remote`: Use the Remote Cache
When an a caching source is omitted, reading and writing are both disabled.
Cache sources use the following values:
* `rw`: Read and write
* `r`: Read only
* `w`: Write only
* None (`local:`) : Does not use cache. Equivalent to omitting the cache source option.
```bash title="Terminal"
# Read from and write to local cache. Only read from Remote Cache.
turbo run build --cache=local:rw,remote:r
# Only read from local cache. Read from and write to Remote Cache.
turbo run build --cache=local:r,remote:rw
# Read from and write to local cache. No Remote Cache activity.
turbo run build --cache=local:rw
# Do not use local cache. Only read from Remote Cache.
turbo run build --cache=local:,remote:r
```
### `--cache-dir `
Default: `.turbo/cache`
Specify the filesystem cache directory.
```bash title="Terminal"
turbo run build --cache-dir="./my-cache"
```
Ensure the directory is in your `.gitignore` when changing it.
The same behavior can also be set via the `TURBO_CACHE_DIR=example/path` system variable.
### `--concurrency `
Default: `10`
Set/limit the maximum concurrency for task execution. Must be an integer greater than or equal to `1` or a percentage value like `50%`.
* Use `1` to force serial execution (one task at a time).
* Use `100%` to use all available logical processors.
* This option is ignored if the [`--parallel`](#--parallel) flag is also passed.
```bash title="Terminal"
turbo run build --concurrency=50%
turbo run test --concurrency=5
```
### `--continue