import { Callout } from "../../../../components/Callout";
import HeartIcon from "@heroicons/react/solid/HeartIcon";
import { Tabs, Tab } from "../../../../components/Tabs";

# Workspaces

Workspaces are the building blocks of your monorepo. Each app and package you add to your monorepo will be **inside its own workspace**.

Workspaces are managed by your [package manager](/repo/docs/handbook/package-installation), so make sure you've set that up first.

## Configuring workspaces

To use workspaces, you must first declare their file system locations to your package manager.

A common convention we recommend is having top-level `apps/` and `packages/` directories. This isn't a requirement - just a suggested directory structure.

The `apps` folder should contain workspaces for launchable apps, such as a [Next.js](https://nextjs.org/) or [Svelte](https://svelte.dev/) app.

The `packages` folder should contain workspaces for packages used by either an app or another package.

<Tabs items={['npm', 'yarn', 'pnpm']} storageKey="selected-pkg-manager">
  <Tab>

    Add the folders you want to configure as workspaces to the `workspaces` field in your root `package.json` file. This field contains a list of workspace folders in the form of globs:

    ```json
    {
      "name": "my-monorepo",
      "version": "1.0.0",
      "workspaces": [
        "docs",
        "apps/*",
        "packages/*"
      ]
    }
    ```

  </Tab>
  <Tab>

    Add the folders you want to configure as workspaces to the `workspaces` field in your root `package.json` file. This field contains a list of workspace folders in the form of globs:

    ```json
    {
      "name": "my-monorepo",
      "version": "1.0.0",
      "workspaces": [
        "docs",
        "apps/*",
        "packages/*"
      ]
    }
    ```

  </Tab>

  <Tab>

    Add the folders you want to configure as workspaces to the `pnpm-workspace.yaml` file that exists in your root directory. This file contains a list of workspace folders in the form of globs:

    ```yaml
    packages:
      - "docs"
      - "apps/*"
      - "packages/*"
    ```

  </Tab>
</Tabs>

```
my-monorepo
├─ docs
├─ apps
│  ├─ api
│  └─ mobile
├─ packages
│  ├─ tsconfig
│  └─ shared-utils
└─ sdk
```

In the example above, all directories inside `my-monorepo/apps/` and `my-monorepo/packages/` are workspaces, and the `my-monorepo/docs` directory itself is also a workspace. `my-monorepo/sdk/` is _not_ a workspace, as it is not included in the workspace configuration.

## Naming workspaces

Each workspace has a unique name, which is specified in its `package.json`:

```json filename="packages/shared-utils/package.json"
{
  "name": "shared-utils"
}
```

This name is used to:

1. Specify which workspace a [package should be installed to](/repo/docs/handbook/package-installation)
1. Use this workspace in other workspaces
1. [Publish packages](/repo/docs/handbook/publishing-packages): it'll be published on npm under the `name` you specify

You can use an npm organization or user scope to avoid collisions with existing packages on npm. For instance, you could use `@mycompany/shared-utils`.

## Workspaces which depend on each other

To use a workspace inside another workspace, you'll need to specify it as a dependency, using its name.

For instance, if we want `apps/docs` to import `packages/shared-utils`, we'd need to add `shared-utils` as a dependency inside `apps/docs/package.json`:

<Tabs items={['npm', 'yarn', 'pnpm']} storageKey="selected-pkg-manager">
  <Tab>

```json filename="apps/docs/package.json"
{
  "dependencies": {
    "shared-utils": "*"
  }
}
```

  </Tab>
  <Tab>
```json filename="apps/docs/package.json"
{
  "dependencies": {
    "shared-utils": "*" // If yarn v2+, use workspace:*
  }
}
```

  </Tab>

  <Tab>
```json filename="apps/docs/package.json"
{
  "dependencies": {
    "shared-utils": "workspace:*"
  }
}
```

  </Tab>
</Tabs>

<Callout type="info">
  The `*` allows us to reference the _latest_ version of the dependency. It
  saves us from needing to bump the versions of our dependency if the versions
  of our packages change.
</Callout>

Just like a normal package, we'd need to run `install` from root afterwards. Once installed, we can use the workspace as if it were any other package from `node_modules`. See our [section on sharing code](/repo/docs/handbook/sharing-code) for more information.

## Managing workspaces

In a monorepo, when you run an `install` command from root, a few things happen:

1. The workspace dependencies you have installed are checked
1. Any workspaces are [symlinked](https://en.wikipedia.org/wiki/Symbolic_link) into `node_modules`, meaning that you can import them like normal packages
1. Other packages are downloaded and installed into `node_modules`

This means that whenever you add/remove workspaces, or change their locations on the filesystem, you'll need to re-run your `install` command from root to set up your workspaces again.

<Callout>
  You **don't need to re-install every time your source code changes** inside a
  package - only when you change the locations (or configuration) of your
  workspaces in some way.
</Callout>

If you run into issues, you may have to delete each `node_modules` folder in your repository and re-run `install` to correct it.
