path.format()

Builds a path string from an object of root, dir, base, name and ext properties.

Signature
path.format(pathObject)
  • Added in Node.js v0.11.15

Parameters

ParameterTypeDescription
$pathObjectObjectAn object describing the path, with any of the properties below.
$pathObject.rootoptionalstringThe filesystem root. Ignored when dir is provided.
$pathObject.diroptionalstringThe directory name. Takes precedence over root.
$pathObject.baseoptionalstringThe final path component including the extension. Takes precedence over name and ext.
$pathObject.nameoptionalstringThe final component without its extension. Used only when base is absent.
$pathObject.extoptionalstringThe 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:

  • dir wins over root. If dir is present, root is ignored entirely — dir is expected to already contain it.
  • base wins over name and ext. If base is 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

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

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.

Example · javascript
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.tsv

Adding 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.

Example · javascript
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.

Example · javascript
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

  • Be the first to comment on this lesson.