How many times have you come across path.join()
and path.resolve()
in Node.js projects without really understanding the difference between them?
In my own experience, I’ve seen different projects with the same structure using one over the other and I couldn’t really understand why. After becoming aware of my lack of knowledge, I decided to investigate and share my learnings with you.
Table of Contents
List of Important Terms
I believe once you understand the terms listed below it will be easier for you to grasp the differences between the two methods.
String: A string is a sequence of characters that are interpreted literally (the exact way it has been written) by a script, e.g.,
"this is a string"
. They must be surrounded by quotation marks if there’s more than one word.Path: A path is simply a string that identifies the location of a file or directory on a computer, e.g.,
"/home/user/Documents/file.ext"
or"/home/user/Downloads/"
. I’m going to use the word ‘file’ here for referring to both files and directories.-
Relative path: A relative path is a string that identifies the location of a file relative to the location of another file.
For instance, let’s assume some user has the following directory structure:
If Downloads is the current working directory (CWD) and the user wants to access a file inside the Documents directory, he would have to navigate up one level, and then go down into the Documents directory. Something like this on POSIX-compliant systems (Linux, MacOS, etc.)
cd ../Documents/file.ext
or like this on Windowscd ..\Documents\file.ext
.Note: On the terminal or prompt we don’t need to surround the string with quotation marks if there are no spaces in the names of the files. Trying to execute
cd ../Documents/my file.ext
would result in an error message. Absolute path: Simplifying, an absolute path is the string that identifies the location of a file relative to the root of the system. For example, instead of trying to access the file from the previous example via a relative path, the user could’ve specified an absolute path like this
cd /home/user/Documents/file.ext
. We can specify an absolute path from any location.Path segment: A path segment is a slice of the path. For example, we have
/home
,/user
and/Documents
as segments of/home/user/Documents/file.ext
.__dirname: This is a Node.js environment variable that specifies the absolute path for the directory which contains the currently executing file.
For instance, if you have webpack.config.js:
console.log(__dirname)
The expected output on the console would be
/home/user/Documents/project
If the webpack.config.js is inside the project
directory.
In other words, __dirname
is simply the string of the absolute path to the file’s location.
-
Path normalization: As you saw, there are differences between the strings used to specify the path on different OSs. Windows uses
\
while POSIX-compliant OSs use/
as a directory separator, just for instance. Path normalization happens when the string is modified so that it conforms to a valid path on the target operating system. If you want to learn more about the steps required to perform path normalization, see https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats.
Brief Recap - How to Change Directories on Terminal/Prompt
.
and ./
represent the CWD;
..
and ../
represent the parent of the CWD;
/
represents the root directory
If you put cd
in front of them, they’ll take you to the desired location.
I said it was going to be brief 😂
What does path.join() do?
The
path.join()
method joins all givenpath
segments together using the platform-specific separator as a delimiter, then normalizes the resulting path.
The syntax is quite simple: path.join(…paths)
, where …paths
is a sequence of segments.
For example, calling path.join("path", "/to", "some", "file")
returns the following string path/to/some/file
in a POSIX-compliant system.
If you don’t understand what the …
mean, take a look at Spread syntax (...).
What does path.resolve() do?
The
path.resolve()
method resolves a sequence of paths or path segments into an absolute path.
Almost identical syntax: path.resolve(…paths)
. This method processes the paths from right to left and when it finds a /
treats it as the root of the system.
For example, calling path.resolve(__dirname, "/path")
would return /path
, because the second argument has a leading /
and thus will be treated as the root of the system.
The key difference
path.join()
simply concatenates segments and its return may or may not result in an absolute path. path.resolve()
always returns an absolute path, using the target operating system’s root as the root or the first argument with a leading /
as the new root.
When should you choose one over the other?
It depends. Does your tool require an absolute path? Then use path.resolve()
. Do you only need to concatenate segments of paths? Use path.join()
.
In practice, I can’t remember seeing path.join()
or path.resolve()
being used without __dirname
, which makes both methods result in an absolute path with the OS’s root being the root.
Again, calling path.resolve(__dirname, "/path")
makes no sense since __dirname
would be totally ignored because the second argument starts with a /
. The following is a valid use case: path.resolve(__dirname, 'dist/assets')
.
Usage examples
Input:
console.log(path.join(__dirname, "path"));
console.log(path.join(__dirname, "/path"));
console.log(path.join(__dirname, "./path"));
console.log(path.join(__dirname, "../path"));
console.log(path.resolve(__dirname, "path"));
console.log(path.resolve(__dirname, "/path"));
console.log(path.resolve(__dirname, "./path"));
console.log(path.resolve(__dirname, "../path"));
Output:
// path.join()
/home/user/some/other/segments/path
/home/user/some/other/segments/path
/home/user/some/other/segments/path
/home/user/some/other/path
//path.resolve()
/home/user/some/other/segments/path
/path
/home/user/some/other/segments/path
/home/user/some/other/path
As you can see, if what you need is an absolute path to the current executing file, you can choose any of the following:
console.log(path.join(__dirname, "path"));
console.log(path.join(__dirname, "/path"));
console.log(path.join(__dirname, "./path"));
console.log(path.resolve(__dirname, "path"));
console.log(path.resolve(__dirname, "./path"));
I think that’s enough.
If you found this article useful, share it with your friends.
See you next time!
Top comments (0)