NodeJSThe path Module

The path Module

node:path builds and dissects filesystem paths correctly — handling the differences between operating systems so you never hard-code a / or \ again. It is pure string manipulation: path never touches the disk. That makes it fast, predictable, and the right tool for every "where is this file?" question.

Why not just concatenate strings?

Because separators differ across platforms, and gluing strings invites bugs — double slashes, missing slashes, wrong direction. path.join normalizes all of it:

JS
import path from 'node:path'

// FRAGILE — wrong separator on Windows, easy to double-up slashes
const bad = 'src' + '/' + 'lib' + '/' + 'index.js'

// ROBUST — correct on every OS, slashes normalized
const good = path.join('src', 'lib', 'index.js')
// → 'src/lib/index.js'  (POSIX)   or   'src\lib\index.js'  (Windows)
The essential functions

Function

Does

Example → result

join(...parts)

Join + normalize segments

join('a', 'b', 'c.js')a/b/c.js

resolve(...parts)

Resolve to an absolute path

resolve('a', 'b')/cwd/a/b

basename(p[, ext])

Last segment

basename('/a/b.js')b.js

dirname(p)

Containing directory

dirname('/a/b.js')/a

extname(p)

File extension

extname('b.tar.gz').gz

parse(p)

Break into an object

{ root, dir, base, name, ext }

format(obj)

Reassemble from parts

inverse of parse

relative(from, to)

Path from one to another

relative('/a/b', '/a/c')../c

isAbsolute(p)

Absolute or not

isAbsolute('/a')true

join vs resolve — the key distinction

Both combine segments, but they differ in one crucial way: resolve always produces an absolute path (walking right-to-left until it has one, falling back to the cwd), while join just glues and normalizes:

JS
path.join('/foo', 'bar', 'baz')      // → '/foo/bar/baz'
path.join('/foo', '../bar')           // → '/bar'    (normalizes '..')

path.resolve('/foo', 'bar')           // → '/foo/bar'
path.resolve('foo', 'bar')            // → '/current/working/dir/foo/bar'
path.resolve('/foo', '/bar')          // → '/bar'  (absolute arg resets the base)
Rule of thumb
Use `join` to assemble a relative path from known pieces. Use `resolve` when you need a guaranteed absolute path — e.g. turning user input or a config value into a concrete location. When building from a module's own folder, combine with `__dirname` (CJS) or `import.meta.dirname` (ESM).
Anchor paths to the file, not the cwd
`process.cwd()` is where node was launched — not where your file lives
A bare relative path like `'./config.json'` is resolved against the *current working directory*, which is wherever the user ran `node` from — not your script's folder. Run the same script from another directory and it breaks. Always anchor bundled-asset paths to the module's own location.

The robust pattern

JS
// CommonJS
const path = require('node:path')
const configPath = path.join(__dirname, 'config.json')

// ES Modules (Node 20.11+)
import path from 'node:path'
const configPath2 = path.join(import.meta.dirname, 'config.json')

Why __dirname and import.meta.dirname behave this way is explained in The Module Wrapper Function.

Cross-platform: posix and win32

By default path uses the conventions of the current OS. When you need to force one — say, parsing a Windows path on a Linux CI server — use the explicit sub-namespaces:

JS
path.win32.join('C:\Users', 'app')    // → 'C:\Users\app'   (always Windows-style)
path.posix.join('/usr', 'local')        // → '/usr/local'      (always POSIX-style)

console.log(path.sep)        // '/' on POSIX, '\' on Windows
console.log(path.delimiter)  // ':' on POSIX, ';' on Windows (PATH separator)
URLs are always POSIX — use `path.posix` for them
Web URL paths use forward slashes on every platform. If you build a URL path with plain `path.join` on Windows, you'll get backslashes and a broken URL. For anything URL-shaped, use `path.posix.join` — or better, the [url module](/nodejs/url-module)'s `URL` class, which handles this correctly.
Dissecting a path with parse

JS
console.log(path.parse('/home/user/report.final.pdf'))
{
  root: '/',
  dir: '/home/user',
  base: 'report.final.pdf',
  ext: '.pdf',
  name: 'report.final'
}
Next
Query the machine your code runs on — CPUs, memory, platform, home directory: [The os Module](/nodejs/os-module).