Using Yarn Workspaces to Create a Monorepo

TribalScale Inc.
TribalScale
Published in
6 min readMar 30, 2023

Written by: Daniel Carmo, Agile Software Engineer, TribalScale

📫 Subscribe to receive our content here.

💬 Have any questions about our development capabilities? Click here to chat with one of our experts!

Today we’re going to explore the use of Yarn Workspaces to create a monorepo of shared components and modules across multiple projects. In a recent project I worked on, we used a monorepo in order to group common components that were used across 2 websites with similar functionality. It was very convenient to have a common libs folder that had code that was shared between the two project. This included analytics, logging, react components, etc. that were shared between the two as common functionality.

Photo by Tara Evans on Unsplash

What are yarn workspaces?

Yarn workspaces allow you to set up multiple projects in a single repository. They allow you to run yarn install to manage and install dependencies across multiple projects. It reduces the need for separate git repositories with overlapping modules and functionality, simplifying them to a single codebase and managed via yarn. We can then create common libraries that are shared across these projects and linked into each component or site that needs them. This will improve the modularity of the code and allow for more reuse across projects.

Prerequisites for this tutorial

  • Node
  • Yarn
  • Visual Studio Code (or your preferred IDE)

How do we create and use our yarn workspace?

In this example we are going to look at creating two reactJS websites that share common components grouped into a workspace. We’ll use the terminal for most of the commands and open the project in Visual Studio Code. First let’s create the folders that will house our monorepo.

$ mkdir yarn-workspace-example && cd yarn-workspace-example

Next we initialize the workspace answering any questions needed

$ yarn init

Next we will create the folder that all our running apps will go into and our first workspace location.

$ mkdir apps

Inside the package.json that was created you can change your project to have a value for "private": "true" as workspaces aren’t shared publicly. We can also add our apps folder to the workspace. So your top level package.json will look like the following:

{
"private": "true",
"name": "yarn-workspace-example",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"workspaces": [
"apps/*"
]
}

Let’s finally use the apps folder to create our react projects which yarn will manage in the workspace. First let’s move into this folder and create the first React project.

$ cd apps
$ yarn create react-app app_one
$ cd ..

Once this is done, you’ll notice that the node_modules that were installed were done so at the top-level of the workspace and not within the app_one folder, but the react-scripts is located in the app_one node_modules/.bin folder. This is one benefit of workspaces, the node_modules are now shared at the top level and only relevant scripts are symlinked into the workspace project itself.

Let’s test out another feature of workspaces. In the package.json of the app_one project, you’ll notice that all the typical react scripts are there. Let’s run the start command for that workspace. Making sure you are at the base folder of your project in the terminal (not the apps/app_one folder) run:

$ yarn workspace app_one start

And just like that, our react site is up and running on localhost:3000 like a standard react project. Using the yarn workspace command will look into the workspaces specified in the top level package.json and see that the app folder contains workspaces. The name of the workspace is then found and the script specified ran against it. That script then exists in the specific projects package.json and runs the appropriate command (in this case react-scripts start).

Let’s create our second reactJS project in the apps folder.

$ cd apps
$ yarn create react-app app_two
$ cd ..

The second react app will be created, and if you look at the folder structure it will be the exact same as the first react app. The node_modules are all contained at the top level of the workspace while the needed scripts are symlinked into the node_modules of the project.

Folder structure

To ensure we can run both react apps at the same time, update the start script in each package.json for each project with a port for the start command.

// apps/app_one/package.json
PORT=3000 react-scripts start
// apps/app_two/package.json
PORT=3001 react-scripts start

With these two projects separated into different ports, we can now run each project individually from our yarn workspace. To run scripts from the package.json of a specific project in the workspace we can use the yarn workspace [folder_name] [script_name]. For example:

$ yarn workspace app_one start
$ yarn workspace app_two start

These two commands will look into the specific workspace folder and run the start script from the package.json. Now you’ll see two separate reactJS projects running on localhost:3000 and localhost:3001.

Now that our react projects are ready to go, let’s start our workspace for common components to share between these projects. Let’s add a folder called libs to the top level yarn project. Go to Visual studio code with the project opened and add a new folder called libs to the top level. Update the package.json on the top level project with the libs/*l to the workspace. Your top level package.json should look like this:

{
"private": "true",
"name": "yarn-workspace-example",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"workspaces": [
"apps/*",
"libs/*"
]
}

Next let’s create our reactJS library using the create-react-library command in the libs folder.

$ cd libs
$ yarn create react-library common
$ cd ..

Run through all the prompts and answer as you see fit, for the Package Manager select yarn and for the Template select default. Once complete we should have a project in the common folder of our libs folder. Let’s compile this project as is and use the ExampleComponent created in our project.

$ yarn install
$ yarn workspace common build

Now open up the apps/app_one/src/App.js file and add the following to the imports list:

$ Import { ExampleComponent } from 'common'

Next let’s add to the App.jsx code using this component, below the anchor for “Learn React” add the following line:

$ <ExampleComponent text="app_one running" />

Lastly let’s run our project from the command line from the workspace:

$ yarn workspace app_one start

Check out the launched server on localhost:3000 and you should see “ExampleComponent: app_one running” below the “Learn React” link. Perform the same steps as above for app_two (using the word “app_two” where “app_one” was used) and you will be able to launch that project on localhost:3001 and see “ExampleComponent: app_two running” below the “Learn React” link.

Conclusion

Yarn workspaces are a great way to organize code from multiple projects into a single repository. It simplifies code sharing between projects and improves the ability to maintain shared code in a common working environment. In our set up we had two separate reactJS projects that shared a common library. They used the same component across the two projects simplifying the code sharing with a yarn workspace.

Daniel is an Agile Software Engineer with experience on a variety of platforms in both development and design. He also enjoys collaborative projects with clients, leading developer projects, and mentoring junior and intermediate developers on everything from code quality to programming knowledge. When he’s not coding, his hobbies include baking, running agility with his dog, raising chickens, and gaming.

TribalScale is a global innovation firm that helps enterprises adapt and thrive in the digital era. We transform teams and processes, build best-in-class digital products, and create disruptive startups. Learn more about us on our website. Connect with us on Twitter, LinkedIn & Facebook!

--

--

TribalScale Inc.
TribalScale

A digital innovation firm with a mission to right the future.