Last updated: 2026-09-14

The path Module

File paths look simple until you have to handle them programmatically across different operating systems, different working directories, and different ways a path can be written. The path module is Node.js's solution to this — a set of utilities for working with file and directory paths correctly, regardless of the platform the code runs on.

It is a small module, but it is used constantly. Almost any code that touches the file system — reading a config file, serving a static asset, resolving an import — benefits from using path instead of manually concatenating strings.


Why Not Just Use String Concatenation?

It is tempting to build a file path by joining strings directly:

const filepath = directory + '/' + filename;

This breaks in several ways. On Windows, the path separator is a backslash (\), not a forward slash. If directory already ends in a slash, you get a doubled separator (folder//file.txt). If filename contains ../ to navigate up a directory, naive concatenation does not resolve it correctly, which can become a security issue when filenames come from user input.

The path module exists specifically to handle these cases correctly and consistently, so you never have to think about separator characters or platform differences yourself.


Importing the Module

const path = require('path');

path is a core module — no installation required, available in every Node.js environment.


Joining Paths — path.join()

path.join() combines multiple path segments into a single path, inserting the correct separator for the current operating system and normalising the result.

const filepath = path.join('uploads', '2026', 'june', 'report.pdf');
console.log(filepath);
// On Linux/macOS: uploads/2026/june/report.pdf
// On Windows: uploads\2026\june\report.pdf

path.join() also resolves .. and . segments and collapses redundant separators:

console.log(path.join('uploads', '..', 'images', 'photo.png'));
// images/photo.png

console.log(path.join('uploads/', '/temp/', '/file.txt'));
// uploads/temp/file.txt — extra slashes are cleaned up

This is the method you reach for by far the most often when constructing a path from multiple pieces.


Resolving Absolute Paths — path.resolve()

path.resolve() builds an absolute path, working from right to left, treating each segment as if it were a cd command, until an absolute path is constructed. If no segment is itself absolute, the current working directory is used as the starting point.

console.log(path.resolve('uploads', 'report.pdf'));
// /home/wariz/project/uploads/report.pdf
// (assuming the current working directory is /home/wariz/project)

console.log(path.resolve('/uploads', 'report.pdf'));
// /uploads/report.pdf — an absolute segment short-circuits the resolution

path.join() vs path.resolve()

This is the distinction that matters most when choosing between the two:

path.join()path.resolve()
ResultA relative or absolute path, depending on inputAlways an absolute path
BehaviourConcatenates segments and normalises themResolves from right to left, like navigating directories
Starting pointNone — purely string-based joiningCurrent working directory, unless an absolute segment is given
console.log(path.join('uploads', 'report.pdf'));
// uploads/report.pdf — relative, as given

console.log(path.resolve('uploads', 'report.pdf'));
// /home/wariz/project/uploads/report.pdf — always absolute

In practice, path.resolve() combined with __dirname (or import.meta.dirname in modern ESM) is the standard way to build a reliable absolute path regardless of where the script is run from:

const configPath = path.resolve(__dirname, 'config.json');

This guarantees the path is correct relative to the file's own location, not relative to whatever directory the process happened to be started from — a common source of bugs when a script is run from a different working directory than expected.


Extracting Parts of a Path

Several path methods extract specific components from a full path string.

const filepath = '/home/wariz/project/uploads/report.pdf';

console.log(path.basename(filepath));        // report.pdf
console.log(path.basename(filepath, '.pdf')); // report — extension removed
console.log(path.dirname(filepath));          // /home/wariz/project/uploads
console.log(path.extname(filepath));          // .pdf

path.basename() returns the final segment of the path — typically the filename. Passing a second argument removes that extension from the result if present.

path.dirname() returns everything except the final segment — the containing directory.

path.extname() returns just the file extension, including the leading dot.

path.parse() — All Components at Once

path.parse() breaks a path into its full set of components in a single call:

const parsed = path.parse('/home/wariz/project/uploads/report.pdf');

console.log(parsed);
// {
//   root: '/',
//   dir: '/home/wariz/project/uploads',
//   base: 'report.pdf',
//   ext: '.pdf',
//   name: 'report'
// }
PropertyMeaning
rootThe root of the filesystem (/ on Linux/macOS, C:\ on Windows)
dirThe directory containing the file
baseThe filename including its extension
extJust the extension
nameThe filename without its extension

path.format() — the Reverse Operation

path.format() takes an object in the same shape returned by path.parse() and builds a path string from it:

const filepath = path.format({
  dir: '/home/wariz/project/uploads',
  name: 'report',
  ext: '.pdf',
});

console.log(filepath); // /home/wariz/project/uploads/report.pdf

Checking If a Path Is Absolute

console.log(path.isAbsolute('/home/wariz/project')); // true
console.log(path.isAbsolute('uploads/report.pdf'));   // false
console.log(path.isAbsolute('C:\\Users\\wariz'));      // true (Windows)

This is useful when accepting a path as input — from a config file, a CLI argument, or a request — and needing to decide whether to resolve it relative to a known base directory or treat it as already complete.


Cross-Platform Considerations

path.sep

The separator character used by the current operating system:

console.log(path.sep); // '/' on Linux/macOS, '\' on Windows

path.delimiter

The character used to separate multiple paths in an environment variable like PATH:

console.log(path.delimiter); // ':' on Linux/macOS, ';' on Windows

path.posix and path.win32

Every method on the path module is normally platform-aware — it behaves according to the operating system the code is currently running on. If you specifically need POSIX-style (Linux/macOS) or Windows-style path handling regardless of the current platform — for example, when processing a path that was generated on a different system than the one your code is running on — path.posix and path.win32 provide explicit, platform-independent versions:

console.log(path.win32.join('uploads', 'report.pdf'));
// uploads\report.pdf — always Windows-style, regardless of current OS

console.log(path.posix.join('uploads', 'report.pdf'));
// uploads/report.pdf — always POSIX-style, regardless of current OS

This matters in practice when, for example, a server running on Linux needs to generate a Windows-compatible file path to include in a downloadable file or a response sent to a Windows client.


A Practical Example — Serving Static Files Safely

A common real-world use of path is constructing a safe file path from user input — for example, serving a requested file while preventing access outside an intended directory (a vulnerability known as path traversal).

const path = require('path');
const fs = require('fs/promises');

const UPLOADS_DIR = path.resolve(__dirname, 'uploads');

async function serveFile(requestedFilename) {
  const requestedPath = path.join(UPLOADS_DIR, requestedFilename);

  // Ensure the resolved path is still inside UPLOADS_DIR
  if (!requestedPath.startsWith(UPLOADS_DIR)) {
    throw new Error('Invalid file path');
  }

  return fs.readFile(requestedPath);
}

Without this check, a malicious filename like ../../etc/passwd passed in as requestedFilename could escape the intended uploads directory entirely. path.join() will normalise the .. segments, but it will not stop the resulting path from pointing outside the intended directory — that check is the developer's responsibility, and comparing the resolved path against the known safe base directory is the standard way to enforce it.


Summary

TaskMethod
Join path segmentspath.join(...segments)
Build an absolute pathpath.resolve(...segments)
Get the filenamepath.basename(filepath)
Get the containing directorypath.dirname(filepath)
Get the file extensionpath.extname(filepath)
Break a path into componentspath.parse(filepath)
Build a path from componentspath.format(pathObject)
Check if a path is absolutepath.isAbsolute(filepath)
Get the OS path separatorpath.sep
Force POSIX-style pathspath.posix.method(...)
Force Windows-style pathspath.win32.method(...)