What’s the Difference Between path.join() and path.resolve()?
Tags: node, javascrip, programming, webdev
Published: 2023-06-12 02:55:05

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](#important-terms) 

- [Brief recap - how to change directories on terminal/prompt](#brief-recap)

- [What does path.join() do?](#join)

- [What does path.resolve() do?](#resolve)

- [The key difference](#key-difference)

- [When should you choose one over the other?](#when)

- [Usage examples](#usage-examples)

## List of Important Terms <a name="important-terms"></a>

I believe once you understand the terms listed below it will be easier for you to grasp the differences between the two methods.

1. **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.

2. **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*.

3. **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:
   <figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bsw05nd69a96siy2jwji.png" alt="Directory structure example" >
<figcaption>Directory structure example</figcaption>
</figure>
    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 Windows `cd ..\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.

4. **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.

5. **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`.

6. **__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**:
```javascript
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.

7. **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 <a name="brief-recap"></a>

`.` 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? <a name="join"></a>

> The `path.join()` method joins all given `path` 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 (...)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax).

## What does path.resolve() do? <a name="resolve"></a>

> 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 <a name="key-difference"></a>

`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? <a name="when"></a>

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 <a name="usage-examples"></a>
Input:
```javascript
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:
```javascript
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!