How to create a fast monorepo with multiple services using Yarn, NX, and Lerna?

Antony Repin
6 min readMar 10, 2023

--

NX, Yarn and Lerna as comics superheroines

Building scalable and maintainable applications can pose a significant challenge for developers, mainly when working with large codebases and multiple services. Fortunately, a monorepo approach and powerful tools like NX, Lerna, and Yarn provide a streamlined development process that enhances code sharing and reusability.

This comprehensive guide aims to assist developers in setting up a monorepo using NX, Lerna, and Yarn. The guide includes detailed information on initial setup, directory structure, dependency management, testing, and deployment.

Upon completing this guide, developers will thoroughly understand how to create scalable and maintainable applications using a monorepo approach. They will also have the necessary tools and knowledge to take their development process to the next level. Let’s dive in!

Find a link to the repository at the bottom of page if interested.

Requirements

Lerna and Yarn for monorepo management.
NX for monorepo packages versioning control.
NestJS as API service which serves to administer requests under /admin API endpoint prefix
Angular application as an admin frontend to NestJS service under monorepo
Docker environment

Roadmap:

∙ Use the shared package for code that any application, like interfaces, enums, etc., can use.
∙ The libs package is intended for libraries for any of the applications.
∙ Dockerize the application with `docker-compose.yml` and `Dockerfile`.

Prerequisites

Yarn

Install Yarn and check the version. From now on, we will use Yarn for package management.

~$ npm install -g yarn
~$ yarn --version

NestJS CLI and Angular CLI

Install NestJS CLI and Angular CLI globally and check their versions:

~$ yarn global add @nestjs/cli @angular/cli
~$ nest -v

Part 1: Monorepo and directory structure setup.

Steps:

1. Initialize your mono repository.
2. Initialize applications (services) as Yarn workspaces.
3. Add NestJS application.
4. Add Angular application.

The Roadmap

Follow these steps to create and run a monorepo with multiple services using Lerna and Yarn.

Initialize monorepo

Create a new empty directory for your mono repo, “lehcode,” in my case.

~$ mkdir [your-repo-name] && cd [your-repo-name]

Initialize the directory as a Yarn workspace by running:

~/lehcode$ yarn init -y
yarn init v1.22.19
success Saved package.json

Add Yarn workspaces definition line into package.json if it is not already there:

  ...,
"workspaces": ["apps/*", "libs/*"]
}

Add Lerna as a development dependency.

Initialize Lerna by running the command; this will create a lerna.json configuration file and the apps directory in the root of the monorepo. Check out Lerna docs for more at https://lerna.js.org/docs/getting-started.

You may need to add -W flag or — ignore-workspace-root-check flag to pass over the workspace root dependency issue

~/lehcode$ yarn add [-W] -D lerna
~/lehcode$ npx lerna init

Initialize services as Yarn workspaces

~/lehcode$ mkdir -p apps/{api,admin}
~/lehcode$ mkdir libs

This command creates a new directory structure in the apps directory of the monorepo, with five subdirectories: API, admin for applications, and libs for shared libraries. These directories will be used for the source code and configuration files for the NestJS backend API service, Angular admin frontend, and various shared libraries.

Add NestJS application to monorepo

The following steps will add the NestJS application to our existing mono-repository as a Yarn workspace.

Create a new NestJS application by running the command.

~/lehcode$ nest new [ --dry-run] --directory apps/api -p yarn --strict

This will generate a new NestJS application and configure Yarn as a package manager in the apps/api directory.
— — strict flag enables strict mode for TypeScript compiler.
— — dry-run or — d flag on the first run simulates the creation of the NestJS application without making actual changes to the file system.

Install the @nrwl/nest package into the root workspace by running the command

# -W tag allows common dependencies installation in root of monorepo
~/lehcode$ yarn add -W -D @nrwl/workspace @nrwl/nx

Configure the NestJS API service to serve to administer requests under /admin entry point and client requests under /client. You can do this by modifying the routing configuration in the app.module.ts file.

Add Angular application to monorepo

Initialize Angular frontend application to administer the backend.

~/lehcode$ nx new app [--dry-run] --create-application --directory=packages/admin --new-project-root=./ --package-manager=yarn --style=scss
? What name would you like to use for the new workspace and initial project? admin
? Would you like to add Angular routing? Yes

The — —dry-run flag on the first run to simulate the creation of an Angular application without applying actual changes.

Go to the package directory:

~/lehcode$ cd packages/admin/

At this stage, the folder structure should look similar to this:

.
├── lerna.json
├── node_modules
├── package.json
├── apps
│ ├── admin
│ │ ├── node_modules
│ │ └── package.json
│ ├── api
│ │ ├── node_modules
│ │ └── package.json
│ ├── shared
│ │ └── package.json
│ ├── common-be
│ │ └── package.json
│ └── common-fe
│ │ └── package.json
└── yarn.lock

You may need to run yarn dev one time manually to answer the prompt about sharing data. Otherwise, the error is issued upon build because it is stalled on the question.

~/lehcode/apps/admin$ yarn dev
yarn run v1.22.19
$ yarn watch
$ ng build --watch --configuration development
? Would you like to share pseudonymous usage data about this project with the Angular Team at Google under Google's Privacy Policy at https://policies.google.com/privacy. For more details and how to change this setting, see https://angular.io/analytics. Yes

After this, the build will go smoothly. Return to repository root:

~/lehcode/apps/admin$ cd ../../

Final Steps

Update the package.json file in each application directory (under ./apps/) to include a name field with the format @<myorg>/<service-name>. This will ensure that each service has a unique package name that can be used to manage it with Yarn and Lerna.

Install the @nrwl/ packages by running the following command.

~/lehcode$ yarn add -W -D @nrwl/workspace @nrwl/nest @nrwl/angular

Common libraries

Add common libraries for the API by running the command

~/lehcode$ nx g @nrwl/workspace:lib libs

Add any common code to the common-be library and configure the API service to use the library by importing it in the app.module.ts file.

Add common libraries for the admin front-end by running the command

~/lehcode$ nx g @nrwl/workspace:lib common-fe

Add any common code to the libs folder and configure the admin frontend to use the library by importing it into the appropriate files.

Part 2. Configure and manage Git versioning in monorepo using NX.

NX provides a convenient way to configure Git versioning in a monorepo, allowing for easy management of version tags. Using the nx version command, you can set up versioning for each package in your monorepo. NX will automatically generate and update version tags in Git as you make changes to the packages.

This feature is handy when multiple packages in your monorepo depend on each other. With Git versioning in place, you can easily track changes and dependencies between packages and ensure the correct versions are used.

The nx version command configures Git versioning in a mono repo managed by NX. This part will guide you through creating and updating version tags in Git for the packages in your monorepo.

1. Ensure you have initialized Git in your monorepo by running the command in the root directory. Run the command $ git init in the root directory of the monorepo.
2. Run the command $ nx version in the root directory of the monorepo. This will open an interactive prompt that will guide you through the versioning process:
* Choose whether to bump the versions of all packages in the monorepo or just a specific package.
* Choose the version to bump (major, minor, or patch).
* Choose if you want to create a Git tag for the new version.
* You will be offered the chance to review the changes made to the package.json files and the Git history.
* Confirm the versioning changes by typing y and pressing Enter.

Follow these steps, and you should have configured Git versioning for your monorepo using NX. NX will automatically update the version numbers in the package.json files and create Git tags for each new version.

Use the nx affected command to determine the impact of changes to the monorepo on other packages and services.

Git repository

Please visit the repository page at https://github.com/lehcode/nestjs-angular-monorepo-starter

References

1. https://angular.io/guide/setup-local
2. https://docs.nestjs.com/first-steps
3. https://yarnpkg.com/features/workspaces
4. https://lerna.js.org/docs/introduction
5. https://nx.dev/recipes

--

--

Antony Repin
Antony Repin

Written by Antony Repin

0 Followers

Experienced frontend developer with a passion for crafting engaging user interfaces. Skilled in modern web technologies and design principles.

No responses yet