Episode # 4 - Creating Your First Basic Monorepo: The Node Modules Trick

In this lesson, we’ll create a basic monorepo using Node.js module resolution and a clever technique we call the Node Modules Trick. This will allow us to structure and manage multiple modules in one repository effectively.


Step 1: Setting Up the Project

Initial Directory Structure

Start by creating a packages folder, which will contain two subfolders:

  1. moduleA

  2. moduleB

Each module will act as a standalone package, designed to be imported and used in other projects.

monorepo-project/
│
└── packages/
    ├── moduleA/
    │   └── index.js
    └── moduleB/
        └── index.js

Writing Module Code

  1. Inside moduleA/index.js:

     console.log('This is module A');
    
  2. Inside moduleB/index.js:

     console.log('This is module B');
    

Testing Module A

Run moduleA using Node.js:

node packages/moduleA/index.js

Output:

This is module A

Step 2: Importing One Module into Another

Now let’s make moduleA call moduleB.

Modify moduleA/index.js:

console.log('This is module A');
require('../moduleB');

Run moduleA again:

node packages/moduleA/index.js

Output:

This is module A  
This is module B

Here, we’re using a relative path (../moduleB) to import moduleB.


Step 3: Requiring Modules by Name

In a real-world scenario, modules should behave like npm packages and be referenced by their name, not relative paths. To do this:

  1. Open moduleB/index.js and update the name:

     console.log('This is module B');
    
  2. Open moduleA/index.js and modify the require statement:

     console.log('This is module A');
     require('moduleB');
    
  3. Now run moduleA:

     node packages/moduleA/index.js
    

Expected Output:

This is module A  
This is module B

Actual Output:

Error: Cannot find module 'moduleB'

Why the Error Occurs

Node.js uses a module resolution strategy where it looks for the node_modules folder to resolve packages. In this case, it:

  1. Looks for a node_modules folder inside packages/moduleA.

  2. If not found, moves to the parent directories, searching for node_modules.

  3. Since no node_modules folder exists, it fails to locate moduleB.


Step 4: The Node Modules Trick

To make Node treat the packages folder as if it were the node_modules folder:

  1. Rename the packages folder to node_modules.

     monorepo-project/
     │
     └── node_modules/
         ├── moduleA/
         │   └── index.js
         └── moduleB/
             └── index.js
    
  2. Run moduleA again:

     node node_modules/moduleA/index.js
    

Output:

This is module A  
This is module B

How This Trick Works

By renaming packages to node_modules:

  • Node.js treats moduleA and moduleB as if they were installed npm packages.

  • The require('moduleB') statement now works because Node resolves the module from the renamed node_modules folder.


Limitations of the Node Modules Trick

While effective for small projects:

  • It creates a non-intuitive directory structure.

  • Doesn’t scale well as the project grows.


Next Steps

In the upcoming lessons, we’ll:

  1. Explore advanced tools and strategies to manage monorepos.

  2. Learn how to use Yarn Workspaces to simplify and professionalize your setup.

This foundational understanding will prepare you to work with more powerful tools for scalable monorepo development! 🚀