import Callout from "../../../../components/Callout"; import HeartIcon from "@heroicons/react/solid/HeartIcon"; import { Tabs, Tab } from "../../../../components/Tabs";
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, so make sure you've set that up first.
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 or Svelte 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">
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/*"
]
}
```
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/*"
]
}
```
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/*"
```
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.
Each workspace has a unique name, which is specified in its package.json
:
{
"name": "shared-utils"
}
This name is used to:
- Specify which workspace a package should be installed to
- Use this workspace in other workspaces
- Publish 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
.
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">
{
"dependencies": {
"shared-utils": "*"
}
}
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 for more information.
In a monorepo, when you run an install
command from root, a few things happen:
- The workspace dependencies you have installed are checked
- Any workspaces are symlinked into
node_modules
, meaning that you can import them like normal packages - 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.
If you run into issues, you may have to delete each node_modules
folder in your repository and re-run install
to correct it.