1128

Is the following the right way to create a directory if it doesn't exist?

It should have full permission for the script and readable by others.

var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
    fs.mkdirSync(dir, 0744);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Whisher
  • 31,320
  • 32
  • 120
  • 201
  • 3
    Possible duplicate of [Node.js create folder or use existing](http://stackoverflow.com/questions/13696148/node-js-create-folder-or-use-existing) – Benny Code Mar 23 '17 at 14:21
  • 4
    Did you try running your script before asking? When I try it I get `TypeError: path.existsSync is not a function` (I am using node v8.10). – Jean Paul Jul 22 '20 at 16:18
  • 3
    it should be `fs.existsSync(dir)` not `path.existsSync(dir)` according to the official api https://nodejs.org/api/fs.html#fsexistssyncpath – xgqfrms Apr 04 '22 at 09:35

24 Answers24

2092

For individual dirs:

var fs = require('fs');
var dir = './tmp';

if (!fs.existsSync(dir)){
    fs.mkdirSync(dir);
}

Or, for nested dirs:

var fs = require('fs');
var dir = './tmp/but/then/nested';

if (!fs.existsSync(dir)){
    fs.mkdirSync(dir, { recursive: true });
}
Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
chovy
  • 72,281
  • 52
  • 227
  • 295
  • 44
    If you're performing this operation on app boot or initialization, then its fine to block execution as you'd do the same thing if you were to do it async. If you're making a directory as a recurring operation then its bad practice but probably won't cause any performance issue, but its a bad habbit none-the-less. Only use for booting your app or otherwise one time operations. – tsturzl Aug 14 '15 at 00:53
  • 28
    existsSync() isn't deprecated, exists() is though - https://nodejs.org/api/fs.html#fs_fs_existssync_path – Ian Chadwick Oct 18 '16 at 11:04
  • 2
    using *`Sync` methods is usually a no-no: don't want to block the event loop – Max Heiber Feb 13 '17 at 21:23
  • 29
    Using sync methods it's fine for local scripts and such, obviously not a good idea for a server. – Pier Sep 03 '17 at 19:58
  • If that block is surrounded by setTimeout, it's async..................... – Bryan Grace Sep 25 '18 at 19:20
  • 3
    What if a file exists with the same name? The code will continue as if there was a directory and probably throw an error later, when it tries writing to files in it. The answer by @josh3736 is much more complete and totally underrated. – Benni Jan 15 '19 at 07:59
  • Nowadays, mkdir can ignore an existing dir. It is async and you needn't worry about race conditions - https://stackoverflow.com/a/48559867/87520 – SamGoody Jun 08 '20 at 12:04
  • 1
    fs.mkdirSync('dir', { recursive: true }) recursive true is mandatory if we want to create recursive folders else it throws error Error: ENOENT: no such file or directory – Rohit Parte Jun 18 '20 at 07:26
  • 2
    `fs.existsSync(dir) || fs.mkdirSync(dir);` is short form of `if` section. – Madan Sapkota Aug 07 '20 at 14:53
  • An explanation (in the answer) would be in order. E.g., why is the way in the question not the correct way and how does this do it right? – Peter Mortensen May 04 '21 at 16:45
240

No, for multiple reasons.

  1. The path module does not have an exists/existsSync method. It is in the fs module. (Perhaps you just made a typo in your question?)

  2. The documentation explicitly discourage you from using exists.

    fs.exists() is an anachronism and exists only for historical reasons. There should almost never be a reason to use it in your own code.

    In particular, checking if a file exists before opening it is an anti-pattern that leaves you vulnerable to race conditions: another process may remove the file between the calls to fs.exists() and fs.open(). Just open the file and handle the error when it's not there.

    Since we're talking about a directory rather than a file, this advice implies you should just unconditionally call mkdir and ignore EEXIST.

  3. In general, you should avoid the *Sync methods. They're blocking, which means absolutely nothing else in your program can happen while you go to the disk. This is a very expensive operation, and the time it takes breaks the core assumption of node's event loop.

    The *Sync methods are usually fine in single-purpose quick scripts (those that do one thing and then exit), but should almost never be used when you're writing a server: your server will be unable to respond to anyone for the entire duration of the I/O requests. If multiple client requests require I/O operations, your server will very quickly grind to a halt.


    The only time I'd consider using *Sync methods in a server application is in an operation that happens once (and only once), at startup. For example, require actually uses readFileSync to load modules.

    Even then, you still have to be careful because lots of synchronous I/O can unnecessarily slow down your server's startup time.


    Instead, you should use the asynchronous I/O methods.

So if we put together those pieces of advice, we get something like this:

function ensureExists(path, mask, cb) {
    if (typeof mask == 'function') { // Allow the `mask` parameter to be optional
        cb = mask;
        mask = 0o744;
    }
    fs.mkdir(path, mask, function(err) {
        if (err) {
            if (err.code == 'EEXIST') cb(null); // Ignore the error if the folder already exists
            else cb(err); // Something else went wrong
        } else cb(null); // Successfully created folder
    });
}

And we can use it like this:

ensureExists(__dirname + '/upload', 0o744, function(err) {
    if (err) // Handle folder creation error
    else // We're all good
});

Of course, this doesn't account for edge cases like

  • What happens if the folder gets deleted while your program is running? (assuming you only check that it exists once during startup)
  • What happens if the folder already exists, but with the wrong permissions?
Federico Baù
  • 6,013
  • 5
  • 30
  • 38
josh3736
  • 139,160
  • 33
  • 216
  • 263
  • 1
    is there a way to avoid SyntaxError: Octal literals are not allowed in strict mode ? – Whisher Jan 19 '14 at 15:37
  • 10
    Write it as a decimal. `0744 == 484`. – josh3736 Jan 19 '14 at 20:21
  • 3
    An alternative is to use a module that extends fs to have this functionality such as https://github.com/jprichardson/node-fs-extra – Bret Jul 28 '14 at 01:00
  • 1
    is this "mask" flag thingy still relevant in 2019? what was the purpose of it? – oldboy Oct 05 '19 at 06:25
  • 1
    It's the [unix file mode](https://en.wikipedia.org/wiki/Modes_(Unix)) -- the directory's read/write permissions. – josh3736 Oct 05 '19 at 06:30
  • 3
    No need to write the mask as a decimal. Prefix it with `0o` instead of just `0`. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Deprecated_octal – andreyrd Oct 14 '19 at 17:46
102

The mkdir method has the ability to recursively create any directories in a path that don't exist, and ignore the ones that do.

From the Node.js v10/11 documentation:

// Creates /tmp/a/apple, regardless of whether `/tmp` and /tmp/a exist.
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
    if (err) throw err;
});

NOTE: You'll need to import the built-in fs module first.

Now here's a little more robust example that leverages native ECMAScript Modules (with flag enabled and .mjs extension), handles non-root paths, and accounts for full pathnames:

import fs from 'fs';
import path from 'path';

function createDirectories(pathname) {
   const __dirname = path.resolve();
   pathname = pathname.replace(/^\.*\/|\/?[^\/]+\.[a-z]+|\/$/g, ''); // Remove leading directory markers, and remove ending /file-name.extension
   fs.mkdir(path.resolve(__dirname, pathname), { recursive: true }, e => {
       if (e) {
           console.error(e);
       } else {
           console.log('Success');
       }
    });
}

You can use it like createDirectories('/components/widget/widget.js');.

And of course, you'd probably want to get more fancy by using promises with async/await to leverage file creation in a more readable synchronous-looking way when the directories are created; but, that's beyond the question's scope.

Federico Baù
  • 6,013
  • 5
  • 30
  • 38
Modular
  • 6,440
  • 2
  • 35
  • 38
  • 4
    Why const __dirname = path.resolve(); and not use the built-in __dirname? – TamusJRoyce Feb 24 '19 at 04:35
  • 2
    @TamusJRoyce __dirname is not available in es modules. Also, path.resolve() is process.cwd(), not __dirname anyway. To get the correct __dirname: https://stackoverflow.com/a/62892482/8280247 – Erik Campobadal Jun 01 '21 at 16:22
  • @ErikCampobadal good detail. yes. I was asking because it did not seem correct. es modules weren't widely used when this comment was posted. And although this question is about node.js. Your answer also compatible with deno - https://stackoverflow.com/a/61829368/458321 – TamusJRoyce Jun 02 '21 at 03:45
  • That was a nice-to-know about demo compatibility. Great one! – Erik Campobadal Jun 04 '21 at 12:03
  • If I wanna create `/var/log/a/b/c/`, how to create them? Right now, it always threw error: Error: EACCES: permission denied, mkdir – Mystic Sep 13 '21 at 02:49
49

With the fs-extra package you can do this with a one-liner:

const fs = require('fs-extra');

const dir = '/tmp/this/path/does/not/exist';
fs.ensureDirSync(dir);
galki
  • 8,149
  • 7
  • 50
  • 62
  • 3
    Such an underrated answer! fs-extra has bacame a must have for me. I think it's an abberration to write 10+ lines juste to check if a folder exists... – TOPKAT May 06 '20 at 10:07
  • 2
    While I would have loved for this to be simply baked in the core functionality, this is the best answer imo. Easy and clean – Hajji Daoud Nov 28 '20 at 11:18
  • I count 3 lines. – chovy Nov 11 '22 at 23:51
45

I have found an npm module that works like a charm for this.

It simply does a recursive mkdir when needed, like a "mkdir -p ".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Toni Gamez
  • 6,819
  • 1
  • 23
  • 18
  • 6
    Why is that better/different from using the built-in mkdir with the { recursive: true } flag? – Daniele Testa Sep 18 '21 at 09:29
  • 4
    I hope this is not sarcastic. Introducing a third-party library just to do something that is so basic and already implemented by a built-in module? This is the exact reason we are seeing the mess in the JS ecosystem. – Zhe Dec 24 '21 at 15:47
39

The one line version:

// Or in TypeScript: import * as fs from 'fs';
const fs = require('fs');
!fs.existsSync(dir) && fs.mkdirSync(dir);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
LeOn - Han Li
  • 9,388
  • 1
  • 65
  • 59
26

solutions

  1. CommonJS
const fs = require('fs');
const path = require('path');

const dir = path.resolve(path.join(__dirname, 'upload');

if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir);
}

// OR
if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir, {
    mode: 0o744, // Not supported on Windows. Default: 0o777
  });
}

  1. ESM

update your package.json file config

{
  // declare using ECMAScript modules(ESM)
  "type": "module",
  //...
}
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

// create one custom `__dirname`, because it doesn't exist in es-module env.
// use `import.meta.url` to get the current module's URL, 
// then get the module's folder absolute path 
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const dir = path.resolve(path.join(__dirname, 'upload');

if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir);
}

// OR
if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir, {
    mode: 0o744, // Not supported on Windows. Default: 0o777
  });
}

update 2022

import { existsSync } from 'node:fs';

refs

NodeJS Version: v18.2.0

https://nodejs.org/api/fs.html#fsexistssyncpath

https://nodejs.org/api/fs.html#fsmkdirsyncpath-options

https://nodejs.org/api/url.html#urlfileurltopathurl

https://github.com/nodejs/help/issues/2907#issuecomment-757446568

ESM: ECMAScript modules

https://nodejs.org/api/esm.html#introduction

xgqfrms
  • 10,077
  • 1
  • 69
  • 68
22

You can just use mkdir and catch the error if the folder exists.
This is async (so best practice) and safe.

fs.mkdir('/path', err => { 
    if (err && err.code != 'EEXIST') throw 'up'
    .. safely do your stuff here  
    })

(Optionally add a second argument with the mode.)


Other thoughts:

  1. You could use then or await by using native promisify.

    const util = require('util'), fs = require('fs');
    const mkdir = util.promisify(fs.mkdir);
    var myFunc = () => { ..do something.. } 
    
    mkdir('/path')
        .then(myFunc)
        .catch(err => { if (err.code != 'EEXIST') throw err; myFunc() })
    
  2. You can make your own promise method, something like (untested):

    let mkdirAsync = (path, mode) => new Promise(
       (resolve, reject) => mkdir (path, mode, 
          err => (err && err.code !== 'EEXIST') ? reject(err) : resolve()
          )
       )
    
  3. For synchronous checking, you can use:

    fs.existsSync(path) || fs.mkdirSync(path)
    
  4. Or you can use a library, the two most popular being

    • mkdirp (just does folders)
    • fsextra (supersets fs, adds lots of useful stuff)
SamGoody
  • 13,758
  • 9
  • 81
  • 91
19

One-line solution: Creates the directory if it does not exist

// import
const fs = require('fs')  // In JavaScript
import * as fs from "fs"  // in TypeScript
import fs from "fs"       // in Typescript

// Use
!fs.existsSync(`./assets/`) && fs.mkdirSync(`./assets/`, { recursive: true })
WasiF
  • 26,101
  • 16
  • 120
  • 128
12

The best solution would be to use the npm module called node-fs-extra. It has a method called mkdir which creates the directory you mentioned. If you give a long directory path, it will create the parent folders automatically. The module is a superset of npm module fs, so you can use all the functions in fs also if you add this module.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Abdul Vajid
  • 1,291
  • 1
  • 15
  • 25
7

The simple and modern answer for node v10 and above

As some answers pointed out, since node 10 you can use recursive:true for mkdir

What is not pointed out yet, is that when using recursive:true, mkdir does not return an error if the directory already existed.

So you can do:

fs.mkdir(dirPath,{recursive:true},(err) => {
    if(err) {
        //note: this does NOT get triggered if the directory already existed
        console.warn(err)
    }
    else{
        //directory now exists 
    }
})

Using promises

Also since node 10, you can get Promise versions of all fs functions by requiring from fs/promises

So putting those two things together, you get this simple solution:

import * as fs from 'fs/promises';

await fs.mkdir(dirPath, {recursive:true}).catch((err) => {
    //decide what you want to do if this failed
    console.error(err);
});

//directory now exists
Flion
  • 10,468
  • 13
  • 48
  • 68
6

Use:

var filessystem = require('fs');
var dir = './path/subpath/';

if (!filessystem.existsSync(dir))
{
    filessystem.mkdirSync(dir);
}
else
{
    console.log("Directory already exist");
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vishnu S Babu
  • 1,570
  • 1
  • 12
  • 23
  • An explanation would be in order (but ***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen May 04 '21 at 16:57
6
var dir = 'path/to/dir';
try {
  fs.mkdirSync(dir);
} catch(e) {
  if (e.code != 'EEXIST') throw e;
}
Sachin Joseph
  • 18,928
  • 4
  • 42
  • 62
Ping.Goblue
  • 576
  • 8
  • 12
  • since `existsSync` is deprecated. – Ping.Goblue Jan 30 '17 at 20:04
  • 4
    For Node.js v7.4.0, the [documentation](https://nodejs.org/api/fs.html#fs_fs_existssync_path) states that `fs.exists()` is deprecated, but `fs.existsSync()` is not. Could you add a link to a ressource saying that `fs.existsSync()` is depreciated? – francis Jan 30 '17 at 21:00
  • 1
    Code-only answers are not very helpful to users who come to this question in the future. Please edit your answer to explain why your code solves the original problem – yivi Jan 30 '17 at 21:42
  • 3
    @francis, hmm, I was looking at Node.js v5,https://nodejs.org/docs/latest-v5.x/api/fs.html#fs_fs_existssync_path – Ping.Goblue Jan 31 '17 at 16:19
  • 1
    Thanks! It seems that the function existed in version 0.12, got deprecated in version 4 and 5 and got restored in version 6 and 7... Kind of a zombi function... – francis Jan 31 '17 at 17:54
  • 1
    Yes, apparently it is **NOT** deprecated now as of `Apr 2018`: https://nodejs.org/api/fs.html#fs_fs_existssync_path – LeOn - Han Li May 03 '18 at 16:02
6

fs.exist() is deprecated. So I have used fs.stat() to check the directory status. If the directory does not exist, fs.stat() throws an error with a message like 'no such file or directory'. Then I have created a directory.

const fs = require('fs').promises;

const dir = './dir';
fs.stat(dir).catch(async (err) => {
  if (err.message.includes('no such file or directory')) {
    await fs.mkdir(dir);
  }
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Caffeines
  • 169
  • 2
  • 5
4

With Node.js 10 + ES6:

import path from 'path';
import fs from 'fs';

(async () => {
  const dir = path.join(__dirname, 'upload');

  try {
    await fs.promises.mkdir(dir);
  } catch (error) {
    if (error.code === 'EEXIST') {
      // Something already exists, but is it a file or directory?
      const lstat = await fs.promises.lstat(dir);

      if (!lstat.isDirectory()) {
        throw error;
      }
    } else {
      throw error;
    }
  }
})();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sdgfsdh
  • 33,689
  • 26
  • 132
  • 245
3

I'd like to add a TypeScript Promise refactor of josh3736's answer.

It does the same thing and has the same edge cases. It just happens to use Promises, TypeScript typedefs, and works with "use strict".

// https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation
const allRWEPermissions = parseInt("0777", 8);

function ensureFilePathExists(path: string, mask: number = allRWEPermissions): Promise<void> {
    return new Promise<void>(
        function(resolve: (value?: void | PromiseLike<void>) => void,
            reject: (reason?: any) => void): void{
            mkdir(path, mask, function(err: NodeJS.ErrnoException): void {
                if (err) {
                    if (err.code === "EEXIST") {
                        resolve(null); // Ignore the error if the folder already exists
                    } else {
                        reject(err); // Something else went wrong
                    }
                } else {
                    resolve(null); // Successfully created folder
                }
            });
    });
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nathan Cooper
  • 6,262
  • 4
  • 36
  • 75
3

For anyone else looking for this in 2023, you can now just do this with async/await - try/catch syntax:

import { stat, mkdir } from 'node:fs/promises';

const checkAndMakeDirectory = async (dir) => {
  try {
    await stat(dir);
  } catch (error) {
    if (error.code === "ENOENT") {
      try {
        await mkdir(dir);
      } catch (err) {
        console.error(err.message);
      }
    }
  }
}
mfdebian
  • 108
  • 1
  • 10
2

You can use the Node.js File System command fs.stat to check if a directory exists and fs.mkdir to create a directory with callback, or fs.mkdirSync to create a directory without callback, like this example:

// First require fs
const fs = require('fs');

// Create directory if not exist (function)
const createDir = (path) => {
    // Check if dir exist
    fs.stat(path, (err, stats) => {
        if (stats.isDirectory()) {
            // Do nothing
        } else {
            // If the given path is not a directory, create a directory
            fs.mkdirSync(path);
        }
    });
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
majid jiji
  • 404
  • 3
  • 7
2

I had to create sub-directories if they didn't exist. I used this:

const path = require('path');
const fs = require('fs');

function ensureDirectoryExists(p) {
    //console.log(ensureDirectoryExists.name, {p});
    const d = path.dirname(p);
    if (d && d !== p) {
        ensureDirectoryExists(d);
    }
    if (!fs.existsSync(d)) {
        fs.mkdirSync(d);
    }
}
Jesus is Lord
  • 14,971
  • 11
  • 66
  • 97
2

From the documentation this is how you do it asynchronously (and recursively):

const fs = require('fs');
const fsPromises = fs.promises;

fsPromises.access(dir, fs.constants.F_OK)
   .catch(async() => {
                await fs.mkdir(dir, { recursive: true }, function(err) {
                    if (err) {
                      console.log(err)
                    }
                  })
    });
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
bobajeff
  • 131
  • 6
1

Here is a little function to recursivlely create directories:

const createDir = (dir) => {
  // This will create a dir given a path such as './folder/subfolder' 
  const splitPath = dir.split('/');
  splitPath.reduce((path, subPath) => {
    let currentPath;
    if(subPath != '.'){
      currentPath = path + '/' + subPath;
      if (!fs.existsSync(currentPath)){
        fs.mkdirSync(currentPath);
      }
    }
    else{
      currentPath = subPath;
    }
    return currentPath
  }, '')
}
MrBlenny
  • 555
  • 6
  • 8
1

my solutions

  1. CommonJS

var fs = require("fs");

var dir = __dirname + '/upload';

// if (!fs.existsSync(dir)) {
//   fs.mkdirSync(dir);
// }

if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir, {
    mode: 0o744,
  });
  // mode's default value is 0o744
}

  1. ESM

update package.json config

{
  //...
  "type": "module",
  //...
}
import fs from "fs";
import path from "path";

// create one custom `__dirname`, because it not exist in es-module env ⚠️
const __dirname = path.resolve();

const dir = __dirname + '/upload';

if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir);
}

// OR
if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir, {
    mode: 0o744,
  });
  // mode's default value is 0o744
}

refs

https://nodejs.org/api/fs.html#fsexistssyncpath

https://github.com/nodejs/help/issues/2907#issuecomment-671782092

xgqfrms
  • 10,077
  • 1
  • 69
  • 68
0

Using async / await:

const mkdirP = async (directory) => {
  try {
    return await fs.mkdirAsync(directory);
  } catch (error) {
    if (error.code != 'EEXIST') {
      throw e;
    }
  }
};

You will need to promisify fs:

import nodeFs from 'fs';
import bluebird from 'bluebird';

const fs = bluebird.promisifyAll(nodeFs);
sdgfsdh
  • 33,689
  • 26
  • 132
  • 245
0

A function to do this asynchronously (adjusted from a similar answer on SO that used sync functions, that I can't find now)

// ensure-directory.js
import { mkdir, access } from 'fs'

/**
 * directoryPath is a path to a directory (no trailing file!)
 */
export default async directoryPath => {
  directoryPath = directoryPath.replace(/\\/g, '/')

  // -- preparation to allow absolute paths as well
  let root = ''
  if (directoryPath[0] === '/') {
    root = '/'
    directoryPath = directoryPath.slice(1)
  } else if (directoryPath[1] === ':') {
    root = directoryPath.slice(0, 3) // c:\
    directoryPath = directoryPath.slice(3)
  }

  // -- create folders all the way down
  const folders = directoryPath.split('/')
  let folderPath = `${root}`
  for (const folder of folders) {
    folderPath = `${folderPath}${folder}/`

    const folderExists = await new Promise(resolve =>
      access(folderPath, error => {
        if (error) {
          resolve(false)
        }
        resolve(true)
      })
    )

    if (!folderExists) {
      await new Promise((resolve, reject) =>
        mkdir(folderPath, error => {
          if (error) {
            reject('Error creating folderPath')
          }
          resolve(folderPath)
        })
      )
    }
  }
}
Zach Smith
  • 8,458
  • 13
  • 59
  • 133