---
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/**", "!.next/cache/**", ".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/**", "!.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 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/**", "!.next/cache/**"],
    },
    "my-sveltekit-app#build": {
      "outputMode": "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 `outputMode` and `inputs` also need to be duplicated.

With Workspace Configurations, `outputMode` and `inputs` are inherited, so
you don't need to duplicate them. You only need to override `outputs`
`my-sveltekit-app` config.

<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
