Contents
Outline
In this blog post, I will introduce how to set up a monorepo using Yarn’s Workspaces.
Blog Series
This blog is a series. Please check other blog posts through the following links.
- [Project Management] Repository Strategy
- [JavaScript] Tools for Monorepo
- [Monorepo] Node JS module resolution
- [Monorepo] Symlink
- [Monorepo] Yarn Workspaces
- [Monorepo] Dependency Hoisting of Yarn Workspaces
- [Monorepo] Command of Yarn Workspaces
- [Monorepo] Creating a Monorepo with pnpm
Yarn Workspaces
In the previous blog post(Tools for Monorepo), I introduced Yarn’s Workspaces.
In this blog post, I will introduce how to set up a monorepo using Yarn’s Workspaces.
- Office document: Workspaces
Yarn’s Workspaces is a feature that allows you to manage multiple projects in a single codebase using the Symlink introduced in the previous blog post. This feature makes it easy to set up a monorepo.
Example
Let’s create an example to check the Workspace feature provided by yarn. First, create a folder and file structure as follows.
.
└── src/
├── module-a/
│ ├── index.js
│ └── package.json
└── module-b/
├── index.js
└── package.json
The package.json of module-a is as follows.
// src/module-a/package.json
{
"name": "module-a",
"version": "1.0.0",
"main": "index.js"
}
The package.json of module-b is as follows.
// src/module-b/package.json
{
"name": "module-b",
"version": "1.0.0",
"main": "index.js"
}
And the index.js of module-b is as follows.
// src/module-b/index.js
console.log('module-b');
Finally, the index.js of module-a is as follows.
// src/module-a/index.js
console.log('module-a');
require('module-b');
After configuring the files like this, run the following command to check if the module is loaded correctly.
node src/module-a/index.js
After running the command, you can see the following error.
module-a
node:internal/modules/cjs/loader:1073
throw err;
^
Error: Cannot find module 'module-b'
Require stack:
- /Users/deku/temp/temp/src/module-a/index.js
at Module._resolveFilename (node:internal/modules/cjs/loader:1070:15)
at Module._load (node:internal/modules/cjs/loader:923:27)
at Module.require (node:internal/modules/cjs/loader:1137:19)
at require (node:internal/modules/helpers:121:18)
at Object.<anonymous> (/Users/deku/temp/temp/src/module-a/index.js:3:1)
at Module._compile (node:internal/modules/cjs/loader:1255:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1309:10)
at Module.load (node:internal/modules/cjs/loader:1113:32)
at Module._load (node:internal/modules/cjs/loader:960:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12) {
code: 'MODULE_NOT_FOUND',
requireStack: [ '/Users/deku/temp/temp/src/module-a/index.js' ]
}
Yarn Workspaces Setup
Now let’s use Yarn’s Workspaces to make module-a use module-b. First, run the following command in the root folder(/) to prepare to use Yarn’s Workspaces.
yarn init -y
After that, the following package.json will be created in the root folder.
{
"name": "monorepo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT"
}
In order to use Yarn’s Workspaces, you need to modify this package.json file as follows.
{
"name": "monorepo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": {
"packages": ["src/module-a", "src/module-b"]
}
}
Monorepo has multiple projects, so it is not necessary to deploy to places like the npm registry. Therefore, set private to true to prevent the monorepo from being deployed. Yarn V1 requires this setting, but Yarn V2 does not require it. It is recommended to set private to true to manage it safely. Of course, individual projects in the monorepo do not need to set private because they can be deployed.
Workspaces can be set as an array([]) or an object({}). Yarn recommends writing it in object format. In Workspaces, an array is created with the key packages and each module is added. You can specify each one like this, but you can also specify all modules simply by using * as follows.
{
"name": "monorepo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": {
"packages": ["src/*"]
}
}
Check Yarn Workspaces
We are now ready to use Yarn’s Workspaces. Now run the following command to install the packages.
yarn install
Then you can see that the node_modules folder is created in the root folder and each module is connected via Symlink.
.
├── node_modules
│ ├── module-a -> ../src/module-a
│ └── module-b -> ../src/module-b
├── package.json
├── src
│ ├── module-a
│ │ ├── index.js
│ │ └── package.json
│ └── module-b
│ ├── index.js
│ └── package.json
└── yarn.lock
Now let’s check if module-a can use module-b by running the following command.
node src/module-a/index.js
Then you can see that module-a is executed without any problems.
module-a
module-b
Of course, since it is connected via Symlink, if you modify the code of module-b, you can use the modified code in module-a. Open the src/module-b/index.js file and modify it as follows.
console.log('module-b!!!');
Then run the following command to check if module-a works correctly.
node src/module-a/index.js
After running the command, you can see that the modified content is displayed correctly.
module-a
module-b!!!
.gitignore
If you are managing the source code with Git, create a .gitignore file and modify it as follows to exclude the node_modules folder from Git.
# .gitignore
node_modules
Completed
Done! We’ve seen how to use Yarn’s Workspaces to set up a monorepo. Yarn’s Workspaces basically works with Symlink, so it’s good to understand Symlink. If you want to know more about Symlink, please see to the previous blog post.
Now you can try using Yarn’s Workspaces to set up a monorepo.
Was my blog helpful? Please leave a comment at the bottom. it will be a great help to me!
App promotion
Deku.Deku created the applications with Flutter.If you have interested, please try to download them for free.



