path.dirname()

Returns the directory portion of a path, excluding the final component.

Signature
path.dirname(path)
  • Added in Node.js v0.1.16

Parameters

ParameterTypeDescription
$pathstringThe path to take the directory portion of.

Return value

stringThe directory name of the path, with trailing directory separators ignored.

Errors

Throws a TypeError (ERR_INVALID_ARG_TYPE) if path is not a string.

Changelog

  • PHP v6.0.0Passing a non-string as the path argument now throws instead of coercing.

path.dirname() returns everything before the last component of a path, mirroring the Unix dirname command. Trailing separators are ignored first, so '/srv/app/public/' yields '/srv/app' rather than '/srv/app/public'.

When to reach for it

Use it to find the folder a file lives in — creating that folder with fs.mkdirSync(path.dirname(file), { recursive: true }) before writing, resolving a relative reference found inside a config file against the config file's own location, or walking upward looking for a marker such as package.json.

What trips people up

A bare filename has no directory part, so path.dirname('index.html') returns '.', not an empty string. The same goes for an empty input. That '.' is usable everywhere a path is expected, but it will surprise code that concatenates strings by hand instead of using path.join().

Because trailing separators are stripped, calling dirname on a directory path gives its parent, not the directory itself. And at the filesystem root the function becomes a fixed point: path.dirname('/') is '/', so an upward-walking loop must test for that or it will never terminate.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Creating the parent directory before writing a file to a nested path
  • Resolving a relative reference inside a config file against that file's own location
  • Walking up the tree to find the nearest package.json or .git directory

Frequently asked questions

How do I get the parent directory of a file path in Node.js?

Call path.dirname(filePath), which returns everything before the last component. For a directory path it returns that directory's parent, because trailing separators are ignored first. To get an absolute parent, wrap it as path.resolve(path.dirname(filePath)).

Why does path.dirname return a dot?

Because the path has no directory component. path.dirname('index.html') and path.dirname('') both return '.', meaning the current working directory. That value works anywhere a path is accepted, but string concatenation will produce './index.html' style results, so use path.join() to recombine.

What is the difference between path.dirname and __dirname?

path.dirname() is a function that extracts the directory part of any path string you hand it. __dirname is a CommonJS variable holding the absolute directory of the currently executing file. In ES modules the equivalent is import.meta.dirname.

More examples

Creating the parent directory before writing

dirname() extracts 'dirname-demo/logs/2024' from the full target so mkdirSync can create the whole chain. This mkdir-the-dirname pattern is the usual reason to call the function at all, since writeFile will not create missing directories itself.

Example · javascript
const path = require('node:path');
const fs = require('node:fs');

const target = path.join('dirname-demo', 'logs', '2024', 'app.log');

fs.mkdirSync(path.dirname(target), { recursive: true });
fs.writeFileSync(target, 'started\n');

console.log('parent:', path.dirname(target));
console.log('contents:', fs.readFileSync(target, 'utf8').trim());

fs.rmSync('dirname-demo', { recursive: true, force: true });
console.log('cleaned up:', fs.existsSync('dirname-demo'));

Walking upward safely

The loop terminates because '/' is its own dirname, so parent === dir becomes true exactly once at the root. Without that comparison the loop would spin forever, which is the classic bug in hand-rolled 'find the nearest package.json' helpers.

Example · javascript
const path = require('node:path');

let dir = path.posix.resolve('/srv/app/public/assets');
const seen = [];

while (true) {
  seen.push(dir);
  const parent = path.posix.dirname(dir);
  if (parent === dir) break;   // hit the root; dirname stopped changing
  dir = parent;
}

console.log(seen);

dirname and basename split a path in two

Together the two functions partition a path with no overlap and no loss, and join() puts it back exactly. This round-trip holds as long as the input has no trailing separator — with one, the trailing separator is dropped and the rejoined string differs.

Example · javascript
const path = require('node:path');

const p = 'src/components/Button.jsx';
const dir = path.dirname(p);
const base = path.basename(p);

console.log('dir: ', dir);
console.log('base:', base);
console.log('rejoined equals original:', path.join(dir, base) === p);

Discussion

  • Be the first to comment on this lesson.