How To Use Absolute Paths In A Node Project (2024)

Avatar photo

By George

5 min read
Bookmark this post

In this post, I will share my findings and what I learned while trying to understand how to use absolute paths in a node project. I found two different methods for doing so, using NODE_PATH and package.json imports, so let’s quickly dive in and hopefully help you out with your own project, too.

Disclaimer!
I hate path resolving, I truly hate it! 😋 It feels so complicated for some reason, especially when you have to decide if you want Typescript, if you want CommonJS, or ESM… it feels that hell breaks loose for something that should be much simpler….! 😡 Now that I got it out of my system, let’s continue.🤭

By the way, if you are here because you are creating a cool side project and want to stop using relative paths hell, this is your post! If, on the other hand, you are a node guru 🧙‍♂️, and you have already climbed the ladders of node wisdom then this is also a post for you. In your case, though, maybe you could add some comments in the end and share your knowledge with us. Don’t be shy! We need Gandalfs like you to guide us! 🌟

Gandalf gif saying "I have no memory of this place".
Source: Giphy

Initializing our project structure

The stack I am using in this post:

  • Ubuntu 22.04.4 LTS
  • npm 10.5.0
  • node 20.12.0

Before explaining how you can change your importing using absolute paths, let’s build a basic project structure so that we are both on the same page when referring to folders/files in our post’s code snippets.

So, nothing fancy here, just an empty folder initialized by npm. I just ran npm init --yes so that my project is initialized automatically with all default values preselected. After doing that, we’ll need some basic folder files and folders:

📦node-paths
 ┣ 📁 server
 ┃   ┗ 📁 src
 ┃       ┣ 📁 controllers
 ┃       ┃  ┗ 📜 UserController.js
 ┃       ┣ 📁 utils
 ┃       ┃  ┗ 📜 helper.js
 ┃       ┗ 📜 app.js
 ┗ 📜 package.json

Typing mkdir -p server/src/controllers will create all structures at once. The -p flag throws no error if the parent folder doesn’t exist, on the contrary, it creates the parent.

Define our importing challenge

Now that we have completed our project’s structure let’s decide on our challenge. Suppose we want to import one helper – in this case validateEmail – from server/src/utils/helper.js

helper.js
function validateEmail(email) {
  // ... validating email logic here
}

module.exports  = {
  validateEmail,
}
JavaScript

to our server/src/controllers/UserController.js file.

UserController.js
class UserController {
  static createUser(userParams) {
    const { email } = userParams;
    if (!validateEmail(email)) {
      throw new Error('Email is not valid');
    }
  }
}
JavaScript

With our current settings, we could do it by adding a relative import

UserController.js
const { validateEmail } = require("../utils/helper");
JavaScript

Well, that’s nice, but we could do much better. Let’s challenge ourselves and change our project’s setting so that we can import by writing:

UserController.js
const { validateEmail } = require("src/utils/helper");
JavaScript

Now be honest! Wouldn’t that be so much better? Great then! Challenge accepted!

I’ve created a basic app.js file which basically imports and calls the createUser method.

app.js
const userController = require("./controllers/UserController.js");

userController.createUser({})
JavaScript

Now that we are ready, I’ll start my node server by running nodemon app.js. (I am using nodemon to watch for file changes and make my life easier, instead of using node).

Using NODE_PATH for absolute paths

One common approach for asking node to search for our imported paths from the root folder is by exploiting NODE_PATH. Based on node’s documentation, we just need to add our root folder path in the NODE_PATH variable.

Let’s do that by adding the following lines in our app’s earliest possible point, in our case, the app.js file’s first lines.

app.js
process.env.NODE_PATH = process.cwd();

require("module").Module._initPaths();

const userController = require("./controllers/UserController.js");

userController.createUser({})
JavaScript

There it is! Nodemon restarted our server and the new import path worked like a charm! 🥳🥳

For those of you who would like to know a bit more, let’s see what we did.

app.js
process.env.NODE_PATH = process.cwd();
JavaScript

In this line of code we are configuring the environment variable NODE_PATH to match our Node process’s current working directory.

NODE_PATH is used when the require method is called to import modules, so we are expanding Node’s search scope by adding one more place to search for, when we ask it to load a new module.

app.js
require("module").Module._initPaths();
JavaScript

This line of code serves to initialize the module paths within our Node.js application. The initPaths method is pivotal in this process, as it handles the initialization.

Using package.json imports for absolute paths

If the first method didn’t suit you or didn’t work, there’s another way to import your files using absolute paths by exploiting imports in your package.json file.

Open your package.json file and add the following highlighted lines

package.json
"main": "app.js",
"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1"
},
"imports": {
  "#helper": "./server/src/utils/helper.js"
}
JSON5

then in our app.js add the following import path

app.js
const { validateEmail } = require("#helper");

const userController = require("./controllers/UserController.js");

userController.createUser({})
JavaScript

Voila! This is another way to import your paths! 😎

Keep in mind that the “Imports” feature was introduced in version 14.6.0 and must start with a #.

Package.json imports and IDEs

If you decide to go with “imports” you could see some errors thrown by your IDE. I had the same issue while working with Webstorm 2023.3.6.

This happens because your IDE does not support the imports field, and you need to help your IDE understand your new setting. (You could also be facing the same issue with other IDEs like VScode.)

I managed to help my Webstorm understand what was going on by adding the following jconfig.json file in the root folder

jsconfig.json
{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "src/*": [
        "server/src/*",
      ]
    }
  }
}
JSON5
DigitalOcean Referral Badge
Tags

node

guest
0 Comments
Inline Feedbacks
View all comments

Continue reading

Front, Programming

What You Need to Know About CSS nth child Selector – A Practical Guide

Front, Programming

Learn How to Select Only the CSS First Child

Front, Programming

Grayscale Backdrop Filter: A Useful Tool To Make Grayish Backgrounds

Front, Programming

How To Calculate CSS Line Height

Front, Programming

Coding Made Easy With CSS Selectors: An Ultimate Guide

Front, Programming

Most Useful HTML Elements for Maximizing Better Results

Front, Programming

CSS Box Sizing – Better Implementations, Less Headaches

Front, Programming

What Is the CSS Box Model in Simple Terms

Front, Programming

CSS Text Decoration In Action: A Powerful Guide

Front, Programming

HTML Formatting Elements Made Simple: With Easy And Practical Examples

Front, Programming

How To Be Creative With Different CSS Border Styles

Front, Programming

How To Work With CSS Syntax: The Correct Way!

Subscribe to our newsletter

Dive into the Fun Side of Tech! Posts, News, and More Delivered to Your Inbox!

Intuit Mailchimp