Node.js create folder or use existing


Question

I already have read the documentation of Node.js and, unless if I missed something, it does not tell what the parameters contain in certain operations, in particular fs.mkdir(). As you can see in the documentation, it's not very much.

Currently, I have this code, which tries to create a folder or use an existing one instead:

fs.mkdir(path,function(e){
    if(!e || (e && e.code === 'EEXIST')){
        //do something with contents
    } else {
        //debug
        console.log(e);
    }
});

But I wonder is this the right way to do it? Is checking for the code EEXIST the right way to know that the folder already exists? I know I can do fs.stat() before making the directory, but that would already be two hits to the filesystem.

Secondly, is there a complete or at least a more detailed documentation of Node.js that contains details as to what error objects contain, what parameters signify etc.

1
168
12/4/2012 4:34:24 AM

Accepted Answer

Good way to do this is to use mkdirp module.

$ npm install mkdirp

Use it to run function that requires the directory. Callback is called after path is created or if path did already exists. Error err is set if mkdirp failed to create directory path.

var mkdirp = require('mkdirp');
mkdirp('/tmp/some/path/foo', function(err) { 

    // path exists unless there was an error

});
229
4/14/2016 9:03:28 AM

Edit: Because this answer is very popular, I have updated it to reflect up-to-date practices.

Using a try {} catch (err) {}, you can achieve this very gracefully without encountering a race condition.

In order to prevent dead time between checking for existence and creating the directory, we simply try to create it straight up, and disregard the error if it is EEXIST (directory already exists).

If the error is not EEXIST, however, we ought to throw an error, because we could be dealing with something like an EPERM or EACCES

We also can use the recursive option of mkdir in order to have a behaviour like mkdir -p (Note: only available in Node >=10.x)

Sync version

const fs = require('fs')

function ensureDirSync (dirpath) {
  try {
    fs.mkdirSync(dirpath, { recursive: true })
  } catch (err) {
    if (err.code !== 'EEXIST') throw err
  }
}

try {
  ensureDirSync('a/b/c')
  console.log('Directory created')
} catch (err) {
  console.error(err)
}

Async version (async/await, modern Node versions)

const fs = require('fs').promises

async function ensureDir (dirpath) {
  try {
    await fs.mkdir(dirpath, { recursive: true })
  } catch (err) {
    if (err.code !== 'EEXIST') throw err
  }
}

async function main () {
  try {
    await ensureDir('a/b/c')
    console.log('Directory created')
  } catch (err) {
    console.error(err)
  }
}

main()

If you prefer not to use the experimental fs.promises API (though it's stable, and is here to stay), you can wrap fs.mkdir yourself:

await new Promise((resolve, reject) => {
  fs.mkdir(dirpath, { recursive: true }, err => err ? reject(err) : resolve())
})

Async version (promises, legacy Node versions)

Note: Because we don't have the new recursive option in pre-10.x Node versions, we have to ensure every part of the path is created.

const fs = require('fs')

function ensureDir (dirpath) {
  return fs.mkdir(dirpath, function (err) {
    if (err.code === 'EEXIST') {
      return Promise.resolve()
    } else {
      return Promise.reject(err)
    }
  })
}

Promise.resolve()
  .then(function () { ensureDir('a') })
  .then(function () { ensureDir('a/b') })
  .then(function () { ensureDir('a/b/c') })
  .then(function () { console.log('Directory created') })
  .catch(function () { console.error(err) })

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon