Vlado Tesanovic CEO / developer at innovic.io, open source lover, lifelong learner. Writing code on GitHub in my free time.

Setting up a monorepo with Lerna for a TypeScript project

4 min read 1142

It is often quite useful to use a single repository for maintaining an entire project with all of the packages in it. There is a rumor that Google and Facebook use a single repository for all of their projects. This solution can be quite handy when a company uses a similar technology and when projects share common dependencies and files.

Popular JS projects like Angular, React, Meteor, Babel, NestJS and many others are using a single repository for all of their packages. In fact, some of them use Lerna for it.

Lerna is a popular and widely used package written in JavaScript for setting and managing multi-package and multi-project single repository for Node.js projects with NPM and GIT.

Lerna has two modes: fixed and independent.

Fixed mode keeps all versions of packages at the same level. This approach is quite popular these days. You may have seen it in Angular.

Independent mode allows us to have different versions per package.

Maintaining all custom packages in a single repository sounds tempting and, as a matter of fact, it is quite easy with Lerna.


We will install Lerna as a global dependency:

npm install -g lerna

Lerna & TypeScript

As Lerna is intended to work with JavaScript and not TypeScript, we will have to adjust the initial configuration for this project.


Lerna works with NPM which stands for Node Package Manager. You will need to create an account there: www.npmjs.com and organization too, as we will create example with scoped packages: @organization/my-project

We made a custom demo for .
No really. Click here to check it out.

No Title

No Description


No Title

No Description


Our packages are going to be public, and for the sake of this project, we will create a Github repository.

Let’s get our hands dirty

Let’s build a simple project which consists of multiple packages for our imaginary project called hospital-sdk.

Create folder hospital and initialize Lerna inside the folder with:

lerna init && npm install

This command will create lerna.json with a default folder structure in it.

  • /packages
  • lerna.json
  • package.json

/packages is a placeholder for our shared packages
lerna.json is a Lerna configuration file

  "packages": [
  "version": "0.0.0"

Lerna doesn’t create .gitignore we will create one with this content:



We will use TypeScript in our project so we can treat it as a shared dependency. Which means we should add it on top level package.json with:

npm install typescript @types/node — save-dev

This is a recommended approach, as we want to use the same tooling across our packages. Alongside TypeScript we will install type declarations for Node.js.

Preparing build script

As we mentioned before, Lerna is intended to be used with Node.js and not with TypeScript. We will need to add additional configuration to make that work with TypeScript.

As this is a demo project, we will assume that we will have a few modules: patient, doctor and scheduler.

Creating packages

To create packages we are going to use thelerna create terminal command from the root of our project.

Thelerna create doctorcommand will guide us through the creation of a new package. The name of the package is important. The name of this package is going to be: @hospital-sdk/doctor

We will repeat the same process for packages patient and scheduler.

The result should be:

As we are using TypeScript for all packages, we will have one common tsconfig.json defined in the root of our project. Our tsconfig.json will look like:

 "compilerOptions": {
   "module": "commonjs",
   "declaration": true,
   "noImplicitAny": false,
   "removeComments": true,
   "noLib": false,
   "emitDecoratorMetadata": true,
   "experimentalDecorators": true,
   "target": "es6",
   "sourceMap": true,
   "lib": [
 "exclude": [

Each individual package will have its own tsconfig.json whose extended root, individual tsconfig.json will look like:

 "extends": "../../tsconfig.json",
 "compilerOptions": {
   "outDir": "./lib"
 "include": [

After we added tsconfig.json in each package, we will create an src folder inside each package with a TypeScript file for that package.

We also need to register tsc script in each individual package.json.

The result should be:

We added simple logic in each .ts file.

We can test our setup by running:

lerna run tsc

The command above will run the tsc script in all created packages:

If all goes well, we will compile TypeScript files from the src folder into lib folder in each package.

If we take a look at package.json for any package in our project, we will see attributes like directories, files, typings, publishConfig and main:


These are very important to us as they control what will be pushed to NPM and what will be the entry point for our library ( main and typings attributes ).


We will create a Github repository for this project and push all of the code there.


Our goal is to publish all packages under the same NPM scope ( organization ). NPM organization can be private as well; in that case you can control who is going to see/use your packages.

We created a public ( free ) organization at npmjs.org:

We have to log in to that organization from terminal:

At this moment, we have organization and build script ready. Let’s glue it all together under one npm script from the root package.json:

 "scripts": {
   "publish": "lerna run tsc && lerna publish"

From terminal we will run:

 npm run publish

Lerna will guide us through the publishing process where we will need to choose a package version and push tags to Github.

If all goes well, we will see message at the end: lerna success published 3 packages.

Verify installation

We will create folder integration in our project directory and install all packages in it:

npm init --yes
npm install ts-node --save-dev
npm install @hospital-sdk/doctor --save
npm install @hospital-sdk/patient --save
npm install @hospital-sdk/scheduler --save

in integration/src/index.ts we can import all our packages and console.log it:

import { Doctor } from "@hospital-sdk/doctor";
import { Patient } from "@hospital-sdk/patient";
import { Scheduler } from "@hospital-sdk/scheduler";

console.log(new Doctor());
console.log(new Scheduler());
console.log(new Patient());

Finally, we can add start script in integration/package.json:

  "scripts": {
   "start": "ts-node src/index.ts" 

and run it from terminal:

Bingo! We successfully called exported classes from our packages.

Lerna commands

There are a couple of Lerna commands worth mentioning:

lerna add Adds npm dependency to all or specific package within a project
lerna bootstrap Install all dependency from all packages within a project


Source code is published on:



200’s only Monitor failed and slow network requests in production

Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.

Writing a lot of TypeScript? Watch the recording of our recent TypeScript meetup to learn about writing more readable code.

TypeScript brings type safety to JavaScript. There can be a tension between type safety and readable code. Watch the recording for a deep dive on some new features of TypeScript 4.4.

LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. .
Vlado Tesanovic CEO / developer at innovic.io, open source lover, lifelong learner. Writing code on GitHub in my free time.

One Reply to “Setting up a monorepo with Lerna for a TypeScript…”

Leave a Reply