Skip to content

Commit

Permalink
Documentation for Workspace Configs (#3788)
Browse files Browse the repository at this point in the history
Co-authored-by: Nicholas Yang <nicholas.yang@vercel.com>
Co-authored-by: Chris Olszewski <chris.olszewski@vercel.com>
Co-authored-by: Rich Haines <hello@richardhaines.dev>
  • Loading branch information
4 people committed Feb 17, 2023
1 parent a313e24 commit 9fec98e
Show file tree
Hide file tree
Showing 2 changed files with 278 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
---
title: Configuring Workspaces
description: Turborepo lets you configure each workspace
---

import Callout from "../../../../../components/Callout";

# Configuring Workspaces

Most monorepos can declare a `turbo.json` in the root directory with a uniform
[pipeline][2] that apply to all workspaces. Sometimes, a monorepo can contain
workspaces that need to configure their tasks differently. To accommodate this,
starting in version 1.8, Turborepo enables you to extend the root configuration
with a `turbo.json` in any workspace. This flexibility enables a more diverse
set of apps and packages to co-exist, and allows workspace 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 workspace of your monorepo with a top-level `extends`
key:

```jsonc filename="apps/my-app/turbo.json"
{
"extends": ["//"],
"pipeline": {
"build": {
// custom configuration for the build task in this workspace
},
// new tasks only available in this workspace
"special-task": {},
}
}
```

<Callout>
For now, the only valid value for the `extends` key is `["//"]`.
`//` is a special name used to identify the root directory of the monorepo.
</Callout>

Configuration in a workspace can override any of [the configurations for a
pipeline task][2]. If you don't include a key, the configuration is inherited
from the extended `turbo.json`.

## Examples

To illustrate, let's look at some use cases.

### Different Frameworks

Let's say your monorepo has multiple [Next.js][5] apps, and one [SvelteKit][6]
app. Both frameworks create their build output with a `build` script in their
respective `package.json`s. You _could_ configure Turborepo to run these tasks
with a single `turbo.json` at the root like this:

```jsonc filename="turbo.json"
{
"pipeline": {
"build": {
"outputs": [".next/**", ".svelte-kit/**"],
}
}
}
```

Notice that both `.next/**` and `.svelte-kit/**` need to be specified as
[`outputs`][7], even though Next.js apps do not generate a `.svelte-kit` directory, and
vice versa. With Workspace Configurations, you can instead add custom
configuration in the SvelteKit workspace in `apps/my-svelte-kit-app/turbo.json`:

```jsonc filename="apps/my-svelte-kit-app/turbo.json"
{
"extends": ["//"],
"pipeline": {
"build": {
"outputs": [".svelte-kit/**"]
}
}
}
```

and remove the config from the root configuration:

```diff filename="turbo.json"
{
"pipeline": {
"build": {
- "outputs": [".next/**", ".svelte-kit/**"]
+ "outputs": [".next/**"]
}
}
}
```

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 workspace `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 filename="turbo.json"
{
"pipeline": {
"build": {
"dependsOn": ["compile"]
},
"compile": {}
}
}
```

With Workspace Configurations, you can move that `compile` task into the
`apps/my-custom-app/turbo.json`,

```json filename="apps/my-app/turbo.json"
{
"extends": ["//"],
"pipeline": {
"build": {
"dependsOn": ["compile"]
},
"compile": {}
}
}
```

and remove it from the root:

```diff filename="turbo.json"
{
"pipeline": {
+ "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 Workspace-specific tasks

At first glance, Workspace Configurations may sound a lot like the
[`workspace#task` syntax][3] in the root `turbo.json`. The features are
similar, but have one significant difference: when you declare a Workspace-specific
in the root `turbo.json`, it _completely_ overwrites the baseline task
configuration. With a Workspace Configuration, the task configuration is merged
instead.

Consider the example of the monorepo with multiple Next.js apps and a Sveltekit
app again. Without a Workspace-specific task, you might configure your root
`turbo.json` like this:

```jsonc filename="turbo.json"
{
"pipeline": {
"build": {
"outputMode": "hash-only",
"inputs": ["src/**"],
"outputs": [".next/**"],
},
"my-sveltekit-app#build": {
"outputMode": "hash-only", // must duplicate this
"inputs": ["src/**"], // must duplicate this
"outputs": [".svelte-kit/**"]
}
}
}
```

This works, but it's important to understand that the `my-sveltekit-app#build`
completely ovewrites `build` for the Sveltekit app. Any other config (such as
`outputMode`) in the `build` task would need to be duplicated. With Workspace
Configurations, you don't need to duplicate any configuration. Just override
what needs to be changed.

<Callout type="info">
Although there are no plans to remove Workspace-specific task configurations,
we expect that Workspace Configurations can be used for most use cases instead.
</Callout>

## Limitations

Although the general idea is the same as the root `turbo.json`, Workspace
Configurations come with a set of guardrails that can prevent workspaces from creating
confusing situations. These guardrails are listed here to make it clear that
they are intentional, rather than accidental:

- Workspace Configurations cannot use [the `workspace#task` syntax][3] as pipeline entries

The `workspace` is inferred based on the _location_ of the config, and it is
not possible to change configuration for another workspace. For example, in a
Workspace Configuration for 'my-nextjs-app':

```jsonc filename="apps/my-nextjs-app/turbo.json"
{
"pipeline": {
"my-nextjs-app#build": {
// ❌ This is not allowed. Even though it's
// referencing the correct workspace, "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 Workspace-specific tasks" section)
},
"my-sveltekit-app#build": {
// ❌ Changing configuration for the "my-sveltekit-app" workspace
// from Workspace Configuraton in "my-nextjs-app" is not allowed.
},
"build": {
// ✅ just use the task name!
},
}
}
```

Note that the `build` task can still depend on a Workspace-specific task:

```jsonc filename="apps/my-nextjs-app/turbo.json"
{
"pipeline": {
"build": {
// ✅ It's still ok to have workspace#task in dependsOn!
"dependsOn": ["some-pkg#compile"]
},
}
}
```

- Workspace Configurations cannot override anything outside the `pipeline` key.

For example, it is not possible to override `globalEnv` or
`globalDependencies`. We expect that monorepo owners should control this
absolutely, and if this config is not _truly_ global, it should not be
configured that way.

- Root turbo.json cannot use the `extends` key.

To avoid creating circular dependencies on workspaces, the root `turbo.json`
cannot extend from anything.

If you have a use case for any of these, please [file an issue][4]!

## 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 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.

[1]: /repo/docs/core-concepts/monorepos/running-tasks#running-tasks-from-the-root
[2]: /repo/docs/reference/configuration#pipeline
[3]: /repo/docs/core-concepts/monorepos/running-tasks#specific-workspace-tasks
[4]: https://github.com/vercel/turbo/issues/new/choose
[5]: https://nextjs.org
[6]: https://kit.svelte.dev/
[7]: /repo/docs/reference/configuration#outputs
15 changes: 12 additions & 3 deletions docs/pages/repo/docs/reference/configuration.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Configuration Options - turbo.json
title: Configuration
description: Learn how to configure Turborepo through `turbo.json`.
---

Expand All @@ -9,13 +9,13 @@ import Link from 'next/link'

# Configuration Options (`turbo.json`)

You can configure the behavior of `turbo` by adding a `turbo.json` file in your monorepo's root (i.e. the same one you specify your `workspaces` key is set for Yarn and npm users).
You can configure the behavior of `turbo` by adding a `turbo.json` file in your monorepo's root directory.

## `globalDependencies`

`type: string[]`

A list of file globs for implicit global hash dependencies. The contents of these files will be included in the global hashing algorithm and affect the hashes of all tasks.
A list of file globs for global hash dependencies. The contents of these files will be included in the global hashing algorithm and affect the hashes of all tasks.
This is useful for busting the cache based on `.env` files (not in Git) or any root level file that impacts workspace tasks (but are not represented in the traditional dependency graph (e.g. a root `tsconfig.json`, `jest.config.js`, `.eslintrc`, etc.)).

<Callout type="info">
Expand Down Expand Up @@ -58,6 +58,13 @@ A list of environment variables for implicit global hash dependencies. The conte
}
```

## `extends`

`type: string[]`

The `extends` key is only valid in Workspace Configurations. It will be
ignored in the root `turbo.json`. Read [the docs to learn more][1].

## `pipeline`

An object representing the task dependency graph of your project. `turbo` interprets these conventions to properly schedule, execute, and cache the outputs of tasks in your project.
Expand Down Expand Up @@ -332,3 +339,5 @@ option, `turbo` can warn you about an invalid configuration.
}
}
```

[1]: /repo/docs/core-concepts/monorepos/configuring-workspaces

1 comment on commit 9fec98e

@vercel
Copy link

@vercel vercel bot commented on 9fec98e Feb 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.