path.dirname()
Returns the directory portion of a path, excluding the final component.
path.dirname(path)- Added in Node.js v0.1.16
Parameters
| Parameter | Type | Description |
|---|---|---|
$path | string | The 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
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.
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.
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.
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