path.format()
Builds a path string from an object of root, dir, base, name and ext properties.
path.format(pathObject)- Added in Node.js v0.11.15
Parameters
| Parameter | Type | Description |
|---|---|---|
$pathObject | Object | An object describing the path, with any of the properties below. |
$pathObject.rootoptional | string | The filesystem root. Ignored when dir is provided. |
$pathObject.diroptional | string | The directory name. Takes precedence over root. |
$pathObject.baseoptional | string | The final path component including the extension. Takes precedence over name and ext. |
$pathObject.nameoptional | string | The final component without its extension. Used only when base is absent. |
$pathObject.extoptional | string | The extension. Used only when base is absent; a leading dot is added if missing. |
Return value
stringA path string assembled from the object's properties.
Errors
Throws a TypeError if pathObject is not an object, or if a supplied property is not a string.
Changelog
- PHP v19.0.0A leading dot is now added to ext automatically if it was not supplied, so ext: 'txt' behaves like ext: '.txt'.
path.format() is the inverse of path.parse(): hand it an object and it assembles a path string. Two precedence rules govern the result, and both catch people out:
dirwins overroot. Ifdiris present,rootis ignored entirely —diris expected to already contain it.basewins overnameandext. Ifbaseis present, the other two are ignored completely and silently.
That second rule is why editing a parsed path so often appears to do nothing. path.parse() fills in all five properties, so an object taken straight from it already has a base. Setting ext = '.md' on that object changes nothing, because base still says 'notes.txt'. Delete or clear base first — or set base to the finished filename yourself.
When to reach for it
Use it whenever you are changing one component of an existing path: swapping an extension, adding a suffix to the stem, or moving a file into a sibling directory. For simply gluing directory names together, path.join() is shorter and normalizes the result, which format() does not do.
Example
When to use it
- Changing a file's extension while keeping its directory and stem
- Adding a suffix such as '.min' to a filename in a build step
- Rebuilding a path after editing individual components from path.parse()
Frequently asked questions
How do I change a file's extension in Node.js?
Parse the path, clear base, set ext, and format it back: path.format({ ...path.parse(p), base: undefined, ext: '.md' }). Clearing base is essential, because base takes priority over name and ext and would otherwise reinstate the original filename.
Why is path.format ignoring my name and ext?
Because the object also has a base property, which takes precedence and causes name and ext to be ignored silently. Objects returned by path.parse() always include base, so delete or undefine it before editing name or ext.
What is the difference between path.format and path.join?
path.format assembles a path from named components — dir, base, name, ext — and concatenates them literally without normalizing. path.join takes an arbitrary list of segments and normalizes the result. Use format when editing one component of an existing path, join when combining directory names.
More examples
Changing an extension the right way
The first line is the bug almost everyone hits once: the output is unchanged because base still holds the old filename. Clearing base, or writing the whole base yourself, both produce the intended result.
const path = require('node:path');
const parsed = path.posix.parse('/srv/app/report.csv');
// wrong: parse() already set base, so it overrides the new ext
console.log(path.posix.format({ ...parsed, ext: '.tsv' }));
// -> /srv/app/report.csv
// right: clear base so name + ext are used
console.log(path.posix.format({ ...parsed, base: undefined, ext: '.tsv' }));
// -> /srv/app/report.tsv
// also right: set base yourself
console.log(path.posix.format({ dir: parsed.dir, base: parsed.name + '.tsv' }));
// -> /srv/app/report.tsvAdding a suffix during a build step
Destructuring only dir, name and ext deliberately leaves base out of the object, so format() is free to use the modified name. The listing shows app.js and app.min.js side by side.
const path = require('node:path');
const fs = require('node:fs');
fs.mkdirSync('format-demo', { recursive: true });
fs.writeFileSync(path.join('format-demo', 'app.js'), 'const x = 1;\n');
const { dir, name, ext } = path.parse(path.join('format-demo', 'app.js'));
const minified = path.format({ dir, name: name + '.min', ext });
fs.writeFileSync(minified, 'const x=1;\n');
console.log('emitted:', minified);
console.log(fs.readdirSync('format-demo').sort());
fs.rmSync('format-demo', { recursive: true, force: true });
console.log('cleaned up:', fs.existsSync('format-demo'));format() does not normalize
Unlike join() and resolve(), format() concatenates the pieces literally and leaves '..' segments in place. Run the result through normalize() or resolve() if the input components might be untidy.
const path = require('node:path');
console.log(path.posix.format({ dir: '/srv/app/..', base: 'a.txt' }));
// -> /srv/app/../a.txt (the '..' survives)
console.log(path.posix.normalize(path.posix.format({ dir: '/srv/app/..', base: 'a.txt' })));
// -> /srv/a.txt
console.log(JSON.stringify(path.posix.format({})));
// -> "" (an empty object yields an empty string)
Discussion