Monorepo with JavaScript: Code Organization for Beginners

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Monorepo with JavaScript: Code Organization for Beginners

As a project grows and common logic that needs to be reused in different parts of the application emerges, developers face the problem of code organization. Many start copying files, creating separate npm packages, or tangled modules. The solution to this problem is a monorepo. In this article, we will break down what a monorepo is, why it is needed in the JavaScript (Node.js) ecosystem, and how to set it up using popular tools. The article is aimed at beginner developers who are already familiar with the basics of Node.js and npm.



What is a Monorepo and Why is it Needed?

A monorepo is an approach to code organization where all projects, libraries, and services are stored in a single repository (e.g., on GitHub). Unlike a multirepo, where each project has its own repository, a monorepo unifies everything in one place.

Main advantages:

  • Unified version control: Easier to manage changes that affect multiple packages.
  • Code reuse: Common utilities, types, and configurations are nearby and do not require publishing to npm.
  • Simplified refactoring: Changes in one package are automatically tested together with others.
  • Unified build and testing: You can run tests for all packages with a single command.

However, monorepos also have disadvantages: they can become too large, and dependency management can become complex. Special tools exist to solve these problems.



Tools for Working with a Monorepo in JavaScript

In the Node.js ecosystem, there are several popular tools for managing a monorepo. We will look at the two most common ones: NPM Workspaces (built into npm) and Lerna.

NPM Workspaces

Starting from npm version 7, built-in support for monorepos was introduced via workspaces. This is a simple and lightweight way to organize code without installing additional packages.

To set it up, simply create a root package.json and specify the folders containing the packages:

// package.json (root){  "name": "my-monorepo",  "private": true,  "workspaces": [    "packages/*"  ]}

Then create the folder structure:

my-monorepo/├── package.json├── packages/│   ├── utils/│   │   ├── package.json│   │   └── index.js│   └── app/│       ├── package.json│       └── index.js

Now, if the app package depends on utils, you can simply specify it in the dependencies:

// packages/app/package.json{  "name": "@my/app",  "dependencies": {    "@my/utils": "*"  }}

After running npm install in the project root, npm will create symbolic links between the packages. This means you can develop both packages simultaneously, and changes in utils will be immediately available in app.



Lerna

Lerna is a more powerful tool that is often used together with NPM Workspaces or Yarn Workspaces. It adds capabilities for publishing packages, versioning, and executing commands across all packages.

Installing Lerna:

npm install -g lerna

Creating the configuration:

lerna init

This will create a lerna.json file and a basic structure. Example configuration:

// lerna.json{  "version": "0.0.0",  "packages": ["packages/*"],  "npmClient": "npm"}

Lerna allows you to run commands across all packages:

lerna run testlerna run build

It also allows you to manage package versions

Blogs

Book Recommendations