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);
} 3 23 Answers
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 });
} 10 No, for multiple reasons.
The
pathmodule does not have anexists/existsSyncmethod. It is in thefsmodule. (Perhaps you just made a typo in your question?)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()andfs.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
mkdirand ignoreEEXIST.In general, you should avoid the *
Syncmethods. 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 *
Syncmethods 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 *
Syncmethods in a server application is in an operation that happens once (and only once), at startup. For example,requireactually usesreadFileSyncto 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?
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.
5I have found an npm module that works like a charm for this.
It simply does a recursive mkdir when needed, like a "mkdir -p ".
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); 2 The one line version:
// Or in TypeScript: import * as fs from 'fs';
const fs = require('fs');
!fs.existsSync(dir) && fs.mkdirSync(dir); 4 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:
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() })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() ) )For synchronous checking, you can use:
fs.existsSync(path) || fs.mkdirSync(path)Or you can use a library, the two most popular being
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 }) 1 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.
var dir = 'path/to/dir';
try { fs.mkdirSync(dir);
} catch(e) { if (e.code != 'EEXIST') throw e;
} 6 Use:
var filessystem = require('fs');
var dir = './path/subpath/';
if (!filessystem.existsSync(dir))
{ filessystem.mkdirSync(dir);
}
else
{ console.log("Directory already exist");
} 1 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); }
}); 0 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; } }
})(); 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".
//
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 } }); });
} 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:
fsNative.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 solutions
- 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 });
}- ESM
update
package.jsonconfig
{ //... "type": "module", //...
}import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
// create one custom `__dirname`, because it does not exist in es-module env ⚠️
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 });
}refs
NodeJS Version: v18.2.0
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); }
} 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); } });
}; 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) } }) }); 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 }, '')
} my solutions
- 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
}- ESM
update
package.jsonconfig
{ //... "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
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); 3 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) }) ) } }
}