A monorepo is a way for software development teams to store code for several projects in the same repository. Monorepos are nice because they keep all the code related to a project in the same place and offer a high degree of flexibility when it comes to organization. One challenging issue is keeping parts of a monorepo separated. For example, if there is a client and a server in the same repository, then with a monorepo, they will share all their dependencies, even if only one of them needs the dependency. One solution to this is Yarn workspaces.
What is a workspace?
A workspace is a directory within a project that has its own package.json file. Each workspace can have its own dependencies, scripts, and versions. By default, every project has one workspace at the root package.json. To make multiple workspaces in a repo, they have to be defined in the root package.json.
How do I make additional workspaces?
You can declare any folder a workspace by adding its name to a “workspaces” array in the root package.json.
{
"workspaces": [
"star",
]
}
</code class="language-typescript">
Then create a package. json file in a subdirectory with the name set to the same name as the workspace.
{
"name": "star",
}
Import code from other workspaces.
Yarn initially prevents code from being imported from one workspace to another. To allow one workspace to access code from another, you’ll have to add it as a dependency. Currently, Yarn recommends adding the workspace as a dependency like so:
{
"dependencies": {
"star": "workspace:*",
}
}
</code class="language-typescript">
Call scripts from all workspaces.
While it is nice that each workspace has its own Yarn scripts, some operations may want to be callable from any workspace in the repo. You can achieve this by adding a ‘:’ in the script name. This is most useful for a start script that must coordinate multiple workspaces.
{
"scripts": {
"start:all":"start server & start client",
}
}
Organizing a Monorepo with Yarn Workspaces
Yarn workspaces are ideal for organizing a monorepo into logically distinct parts. They keep scripts and dependencies organized. And, they document which parts of the repo are dependent on others.