# What Happens When You Import Anything in Node.js?

Ever wondered what really happens when you import a module in Node.js? How Node.js figures out where to find the file? Or why you sometimes get an error like:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1741291904292/77f3800b-6b58-4d13-9bb6-39e7d43f58fb.png align="center")

To fully understand **imports**, we must first understand **exports** and how Node.js resolves modules. Let’s dive right in.

## Exports — How modules define what can be imported

Originally, JavaScript code in Node.js was packaged using CommonJS modules.

> Node.js considers each file as a separate module.

For instance, if you had a file called `index.js` with the following contents;

```javascript
const articles = require("./article.js")

const text = "This is an article i wrote about the Node.js module resolution algorithm."
const title = "What Happens When You Import Anything in Node.js?"

console.log("The word count of the article is: ${article.wordCount(text)}")
console.log("The length of the title is ${article.titleLength(title)}")
```

First off `index.js` loads the module `article.js` that is located in a directory relative to itself. The contents of `article.js` are as below;

```javascript
function wordCount(text) {
    return text.split(/\s+/).length;  // Splitting text into words and counting them
}

function titleLength(title) {
    return title.length;  // Returning the length of the title string
}

// Exporting the functions
exports.wordCount = wordCount;
exports.titleLength = titleLength;
```

The module `article.js` exports the functions `wordCount()` and `titleLength()`.

But, Node.js also supports ECMAScript standard which is supported by web browsers and other JavaScript runtimes. According to [Node.js Documentation](https://nodejs.org/api/esm.html#modules-ecmascript-modules), ECMAScript modules are the official standard format to package JavaScript code for reuse. Modules are defined using a variety of [import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) and [export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) statements.

> A module needs to export something before it can be imported.

Node.js as well allows modules to explicitely define *exports* in `package.json` as seen below;

```json
{
    "name": "my-package",
    "exports": {
            "./publications": "./article.js"
        }
}
```

In the above `package.json` file, the exports defines what is exposed by the module. This can be handy when one needs to prevent unintended access to internal files.

The functions from module `article.js` can now be imported as below;

```javascript
import { wordCount, titleLength } from "my-package/publications"

const text = "This is an article i wrote about the Node.js module resolution algorithm."
const title = "What Happens When You Import Anything in Node.js?"

console.log("The word count of the article is: ${wordCount(text)}")
console.log("The length of the title is ${titleLength(title)}")
```

## The Resolution Algorithm — How Node.js Resolves Imports

Node.js executes a strict procedure which is the resolution algorithm in order to check if `some-module` exists and if it does, where it is located in the file system. Several checks and tests are performed before a deduction is made.

Whenever you write;

```javascript
import { anything } from "some-module"
```

The checks made are made for;

* Core modules
    
* Relative modules
    
* NPM packages
    
* Directories
    
* Alias Modules
    

### Check 1: Is It A Core Module?

Node.js core modules are a set of modules which you can use off-the-self without manual installation.

Some core modules include; `fs`, `dns`, `events`, `os`, `path`, `url`, `util`, `stream`, and so many more….

Node.js will first check if the import matches one of the inbuilt modules.

```javascript
import fs from "fs" // Core Module
```

If its a core module, it will immediately get loaded.

### Check 2: Is It A Relative Module?

Secondly, Node.js will check if the module name starts with `/`, `./`, or `../`. If it does, then the proceeding content will be treated as a file path and search for the module location with commence.

```javascript
import { anything } from "/some-module"
import { something } from "./some-module"
import { things } from "../some-module"
```

If the module name starts with `/`, a search at the root of the file system will be made.

If the module name starts with `./` or `../` , a search will be made relative to the location of the current file.

### Check 3: Is It An NPM Package?

This check search through `node_modules`.

If a module is not a core module and neither a relative module, Node.js will assume it a package installed from [npm registry](https://www.npmjs.com/) and will commence a search through the `node_modules` directory.

```javascript
import { useDocumentQuery } from "@tanstack-query-firebase/react" // Searches node_modules for @tanstack-query-firebase
```

Node.js will check if `node_modules/@tanstack-query-firebase/react/package.json` exists.

If the `node_modules/@tanstack-query-firebase/react/package.json` exists, a check if there exists an `exports` field in the `package.json` . If exists, what is exposed by the `export` will be resolved.

```json
{
    "name": "my-package",
    "exports": {
            "./publications": "./article.js"
        }
}
```

If the `node_modules/@tanstack-query-firebase/react/package.json` exists, and doesn’t have an `exports` field in the `package.json`. The `main` field will them be considered and its value will be resolved.

```json
{
    "name": "my-package",
    "main": "./article.js"
}
```

In the event that a `main` field doesn’t exist in the `package.json`, an available `index.js` or `index.mjs` file will be considered.

If `@tanstack-query-firebase` is not found at the current directory level, Node.js will move subsequent levels upwards the file system while checking for it.

```bash
 ./node_modules/@tanstack-query-firebase  
../node_modules/@tanstack-query-firebase  
../../node_modules/@tanstack-query-firebase
```

> Packages installed at the root of your file system are ideally be available to all Node.js apps on your system.

### Check 4: Is It A Directory?

If the import refers to a directory, Node.js will search for a `package.json` file in that directory. In the `package.json`, a `main` field as an entry will be looked out for.

```javascript
import utils from "./utils"
```

If a `package.json` doesn’t exist, an `index.js` or `index.mjs` will be searched.

```bash
./utils/package.json (looks for "main" field)  
./utils/index.js  
./utils/index.mjs
```

### Check 5: Additional Checks and Considerations

Additionally, Node.js will check for an ESM vs CommonJS Compatibility.

If you import an ESM (`.mjs`) module into a CommonJS (`.cjs`) file, or vice versa, Node.js may throw an error.

```javascript
// CommonJS (require)
const package = require('some-esm-module'); // Error if it's an ESM package
```

To avoid conflicts, ensure your `package.json` has:

```json
{
  "type": "module"
}
```

or explicitly use `.mjs` or `.cjs` extensions.

## Conclusion

The Node.js Resolution Algorithm gives insight into what happens under the hood, every time we import anything in Node.js.

## References

### [https://nodejs.org/api/packages.html#exports](https://nodejs.org/api/packages.html#exports)

### [https://nodejs.org/api/modules.html#modules-commonjs-modules](https://nodejs.org/api/modules.html#modules-commonjs-modules)

[https://nodejs.org/api/esm.html#modules-ecmascript-modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules)
