290

I'm trying to create a full path if it doesn't exist.

The code looks like this:

var fs = require('fs'); if (!fs.existsSync(newDest)) fs.mkdirSync(newDest); 

This code works great as long as there is only one subdirectory (a newDest like 'dir1'). However, when there is a directory path like ('dir1/dir2') it fails with

Error: ENOENT, no such file or directory

I'd like to be able to create the full path with as few lines of code as necessary.

I read there is a recursive option on fs and tried it like this:

var fs = require('fs'); if (!fs.existsSync(newDest)) fs.mkdirSync(newDest, '0777', true); 

I feel like it should be that simple to recursively create a directory that doesn't exist. Am I missing something or do I need to parse the path and check each directory and create it if it doesn't already exist?

I'm pretty new to Node.js. Maybe I'm using an old version of FS?

3
  • 1
    github.com/substack/node-mkdirp and all sorts of other solutions on this Google search. Commented Jul 27, 2015 at 5:58
  • 5
    @AndyRay This StackOverflow question is now the top result in google for this question, which is funny because that means it's recursi.... Commented Jan 31, 2019 at 14:47
  • 1
    That was a problem on older versions of Node, updating to Node 12+ solves the problem Commented Jun 20, 2019 at 16:33

23 Answers 23

772

Node.js version 10.12.0 and later

Node.js version 10.12.0 has added a native support for both mkdir and mkdirSync to create a directory recursively with recursive: true option as the following:

fs.mkdirSync(targetDir, { recursive: true }); 

And if you prefer fs Promises API, you can write

fs.promises.mkdir(targetDir, { recursive: true }); 

Before Node.js version 10.12.0

Create directories recursively if they do not exist! (Zero dependencies)

const fs = require('fs'); const path = require('path'); function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) { const sep = path.sep; const initDir = path.isAbsolute(targetDir) ? sep : ''; const baseDir = isRelativeToScript ? __dirname : '.'; return targetDir.split(sep).reduce((parentDir, childDir) => { const curDir = path.resolve(baseDir, parentDir, childDir); try { fs.mkdirSync(curDir); } catch (err) { if (err.code === 'EEXIST') { // curDir already exists! return curDir; } // To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows. if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure. throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`); } const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1; if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) { throw err; // Throw if it's just the last created dir. } } return curDir; }, initDir); } 

Usage

// Default, make directories relative to current working directory. mkDirByPathSync('path/to/dir'); // Make directories relative to the current script. mkDirByPathSync('path/to/dir', {isRelativeToScript: true}); // Make directories with an absolute path. mkDirByPathSync('/path/to/dir'); 

Demo

Try It!

Explanations

  • This solution handles platform-specific errors like EISDIR for Mac and EPERM and EACCES for Windows.
  • This solution handles both relative and absolute paths.
  • In the case of relative paths, target directories will be created (resolved) in the current working directory. To Resolve them relative to the current script directory, pass {isRelativeToScript: true}.
  • Using path.sep and path.resolve(), not just / concatenation, to avoid cross-platform issues.
  • Using fs.mkdirSync and handling the error with try/catch if thrown to handle race conditions: another process may add the file between the calls to fs.existsSync() and fs.mkdirSync() and causes an exception.
    • The other way to achieve that could be checking if a file exists then creating it, I.e, if (!fs.existsSync(curDir) fs.mkdirSync(curDir);. But this is an antipattern that leaves the code vulnerable to race conditions.
  • Requires Node.js v6 and newer to support destructuring assignment.
Sign up to request clarification or add additional context in comments.

42 Comments

Upvote for the easy, recursive response not requiring an additional library or approach!
Missing require statements: const fs = require('fs'); const path = require('path');
@ChristopherBull, intentionally not added just to focus on the logic, but anyways, I added them. Thanks ;)
12 lines of solid code, zero dependencies, I'll take it every time.
@Mouneer on Mac OS X 10.12.6, the error thrown when trying to create "/" after passing in an absolute path is "EISDIR" (Error: EISDIR: illegal operation on a directory, mkdir '/'). I think probably checking for dir existence is still the best cross-platform way to go (acknowledging it will be slower).
|
88

A more robust answer is to use use mkdirp.

var mkdirp = require('mkdirp'); mkdirp('/path/to/dir', function (err) { if (err) console.error(err) else console.log('dir created') }); 

Then proceed to write the file into the full path with:

fs.writeFile ('/path/to/dir/file.dat'.... 

3 Comments

Prefer this answer since you are importing just what you need, not an entire library
Congrats on the Populist badge ;-)
57

One option is to use the shelljs module.

npm install shelljs.

var shell = require('shelljs'); shell.mkdir('-p', fullPath); 

From that page:

Available options:

p: full path (will create intermediate directories if necessary)

As others have noted, there are other more focused modules. But, outside of mkdirp, it has tons of other useful shell operations (like which, grep, etc.), and it works on Windows and Unix-like systems.

Comments suggest this doesn't work on systems that don't have mkdir cli instances. That is not the case. That's the point of shelljs; create a portable cross-platform set of shell-like functions. It even works on Windows.

7 Comments

Thanks! I ended up using exec (I was already using this) and it worked like a charm. var exec = require('child_process').exec; var command = "mkdir -p '" + newDest + "'"; var options = {}; var after = function(error, stdout, stderr) { console.log('error', error); console.log('stdout', stdout); console.log('stderr', stderr); } exec(command, options, after);
This option may break on node.js platforms that don't have a command line mkdir instance (i.e., non-Linux-y hosts) so it isn't portable, if that matters.
@cshotton - are you referring to the comment or the answer? shelljs works even on windows. exec mkdir -p (the comment) of course doesn't.
this is not a solution, this is an alternative to the solution. context: pics.onsizzle.com/…
@NikaKasradze this is a possible solution and works. All solutions are alternatives.
|
52

fs-extra adds file system methods that aren't included in the native fs module. It is a drop-in replacement for fs.

Install fs-extra:

npm install --save fs-extra 

Usage:

const fs = require("fs-extra"); // Make sure the output directory is there. fs.ensureDirSync(newDest); 

There are sync and async options.

Reference: ensureDir(dir[,options][,callback])

2 Comments

This is the best answer! Most of us already have fs-extra in the app anyway.
This would be great if it offered a possibility to use memfs for unit testing. It doesn't :-( github.com/jprichardson/node-fs-extra/issues/274
33

Using reduce, we can verify if each path exists and create it if necessary. Also this way, I think, is easier to follow. We should use path.sep to get the proper platform-specific path segment separator.

const path = require('path'); // Path separators could change depending on the platform const pathToCreate = 'path/to/directory'; pathToCreate .split(path.sep) .reduce((prevPath, folder) => { const currentPath = path.join(prevPath, folder, path.sep); if (!fs.existsSync(currentPath)){ fs.mkdirSync(currentPath); } return currentPath; }, ''); 

4 Comments

When giving an answer it is preferable to give some explanation as to WHY your answer is the one.
Sorry, you are right, I think this way it is cleaner and easier to follow
@josebui I think it is better using "path.sep" instead of forward slash (/) to avoid environment specefic issues.
good solution because doesn't require node >=10 like the other answers
30

This feature has been added to Node.js in version 10.12.0, so it's as easy as passing an option {recursive: true} as second argument to the fs.mkdir() call.

See the example in the official documentation.

There isn't any need for external modules or your own implementation.

3 Comments

I found the related pull request github.com/nodejs/node/pull/23313
It will throw error when directory exist and stop. Use a try catch block can make it keep creating other non-exist folder.
This should be the accepted answer. It does not throw if the directory already exists, and can be used with async/await via fs.promises.mkdir.
12

I know this is an old question, but Node.js v10.12.0 now supports this natively with the recursive option set to true. fs.mkdir:

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

1 Comment

Isn't this a repeat of several previous answers?
5

Now with Node.js 10.12.0 or later, you can use fs.mkdirSync(path, { recursive: true }).

See fs.mkdirSync.

Comments

3

Example for Windows (no extra dependencies and error handling)

const path = require('path'); const fs = require('fs'); let dir = "C:\\temp\\dir1\\dir2\\dir3"; function createDirRecursively(dir) { if (!fs.existsSync(dir)) { createDirRecursively(path.join(dir, "..")); fs.mkdirSync(dir); } } createDirRecursively(dir); //creates dir1\dir2\dir3 in C:\temp 

Comments

2

You can simply check if the folder exists or not in the path recursively and make the folder as you check if they are not present. (Note: That doesn't require any external library)

function checkAndCreateDestinationPath (fileDestination) { const dirPath = fileDestination.split('/'); dirPath.forEach((element, index) => { if(!fs.existsSync(dirPath.slice(0, index + 1).join('/'))) { fs.mkdirSync(dirPath.slice(0, index + 1).join('/')); } }); } 

Comments

2

You can use the following function:

const recursiveUpload = (path: string) => { const paths = path.split("/") const fullPath = paths.reduce((accumulator, current) => { fs.mkdirSync(accumulator) return `${accumulator}/${current}` }) fs.mkdirSync(fullPath) return fullPath } 

It:

  1. Creates a paths variable, where it stores every path by itself as an element of the array.

  2. Adds "/" at the end of each element in the array.

  3. Makes for the cycle:

    1. Creates a directory from the concatenation of array elements which indexes are from 0 to current iteration. Basically, it is recursive.

By the way, in Node.js v10.12.0 you can use recursive path creation by giving it as the additional argument.

fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => { if (err) throw err; }); 

See also fs.mkdirSync(path[, options]).

Comments

1

Here's a solution without recursion that works by splitting the path and then left-to-right building it back up again:

function mkdirRecursiveSync(path) { let paths = path.split(path.delimiter); let fullPath = ''; paths.forEach((path) => { if (fullPath === '') { fullPath = path; } else { fullPath = fullPath + '/' + path; } if (!fs.existsSync(fullPath)) { fs.mkdirSync(fullPath); } }); }; 

For those concerned about Windows vs Linux compatibility, simply replace the forward slash with double backslash '\' in both occurrence above, but to be honest we are talking about Node.js' fs, not Windows command line. The former is pretty forgiving, and the above code will simply work on Windows and is more a complete solution cross platform.

9 Comments

files on windows are handled with backslash not forward slash. Your code simply won't work there. C:\data\test ...
Edited but suggest you validate your comment. On node try the following and see what happens var fs = require('fs') fs.mkdirSync('test') fs.mkdirSync('test\\test1') fs.mkdirSync('test/test2')
Whatever you're saying.., my down vote still stays until you learn to write better code.
Haha. Ok, I'll work really hard on learning how to write better code. BTW most answers above, including the OP, use forward slashes. Suggest you stop trolling.
path.sep is coming through as either / or \\ for me. path.delimiter is : or ;.
|
0

An asynchronous way to create directories recursively:

import fs from 'fs' const mkdirRecursive = function(path, callback) { let controlledPaths = [] let paths = path.split( '/' // Put each path in an array ).filter( p => p != '.' // Skip root path indicator (.) ).reduce((memo, item) => { // Previous item prepended to each item so we preserve realpaths const prevItem = memo.length > 0 ? memo.join('/').replace(/\.\//g, '')+'/' : '' controlledPaths.push('./'+prevItem+item) return [...memo, './'+prevItem+item] }, []).map(dir => { fs.mkdir(dir, err => { if (err && err.code != 'EEXIST') throw err // Delete created directory (or skipped) from controlledPath controlledPaths.splice(controlledPaths.indexOf(dir), 1) if (controlledPaths.length === 0) { return callback() } }) }) } // Usage mkdirRecursive('./photos/recent', () => { console.log('Directories created succesfully!') }) 

Comments

0

As clean as this :)

function makedir(fullpath) { let destination_split = fullpath.replace('/', '\\').split('\\') let path_builder = destination_split[0] $.each(destination_split, function (i, path_segment) { if (i < 1) return true path_builder += '\\' + path_segment if (!fs.existsSync(path_builder)) { fs.mkdirSync(path_builder) } }) } 

1 Comment

An explanation would be in order. E.g., what is the idea? What is the gist? How is it different from previous answers? See also "Explanation is vital for a good answer.". But please, *** *** *** *** *** *** *** *** *** without *** *** *** *** *** *** *** *** *** "Edit:", "Update:", or similar.
0

I solved the problem this way - similar to other recursive answers but to me this is much easier to understand and read.

const path = require('path'); const fs = require('fs'); function mkdirRecurse(inputPath) { if (fs.existsSync(inputPath)) { return; } const basePath = path.dirname(inputPath); if (fs.existsSync(basePath)) { fs.mkdirSync(inputPath); } mkdirRecurse(basePath); } 

2 Comments

if i pass in a path /does/not/exist it only creates the first level does folder ;-(
Ok, I don't know why but I would have thought that would be extremely easy to see why in your case in debugging.
0

Here's my imperative version of mkdirp for Node.js.

function mkdirSyncP(location) { let normalizedPath = path.normalize(location); let parsedPathObj = path.parse(normalizedPath); let curDir = parsedPathObj.root; let folders = parsedPathObj.dir.split(path.sep); folders.push(parsedPathObj.base); for(let part of folders) { curDir = path.join(curDir, part); if (!fs.existsSync(curDir)) { fs.mkdirSync(curDir); } } } 

Comments

0

Use this approach:

if (!fs.existsSync(pathToFile)) { var dirName = ""; var filePathSplit = pathToFile.split('/'); for (var index = 0; index < filePathSplit.length; index++) { dirName += filePathSplit[index] + '/'; if (!fs.existsSync(dirName)) fs.mkdirSync(dirName); } } 

This works for relative path.

Comments

0

Based on mouneer's zero-dependencies answer, here's a slightly more beginner friendly TypeScript variant, as a module:

import * as fs from 'fs'; import * as path from 'path'; /** * Recursively creates directories until `targetDir` is valid. * @param targetDir: Target directory path to be created recursively. * @param isRelative: Is the provided `targetDir` a relative path? */ export function mkdirRecursiveSync(targetDir: string, isRelative = false) { const sep = path.sep; const initDir = path.isAbsolute(targetDir) ? sep : ''; const baseDir = isRelative ? __dirname : '.'; targetDir.split(sep).reduce((prevDirPath, dirToCreate) => { const curDirPathToCreate = path.resolve(baseDir, prevDirPath, dirToCreate); try { fs.mkdirSync(curDirPathToCreate); } catch (err) { if (err.code !== 'EEXIST') { throw err; } // caught EEXIST error if curDirPathToCreate already existed (not a problem for us). } return curDirPathToCreate; // Becomes prevDirPath on the next call to reduce }, initDir); } 

Comments

0

Use:

const fs = require('fs'); try { fs.mkdirSync(path, { recursive: true }); } catch (error) { // This makes the script keep running, even when the folder already exists console.log(error); } 

Comments

0

I had issues with the recursive option of fs.mkdir, so I made a function that does the following:

  1. Creates a list of all directories, starting with the final target directory and working up to the root parent.

  2. Creates a new list of needed directories for the mkdir function to work

  3. Makes each directory needed, including the final

     function createDirectoryIfNotExistsRecursive(dirname) { return new Promise((resolve, reject) => { const fs = require('fs'); var slash = '/'; // Backward slashes for Windows if(require('os').platform() === 'win32') { slash = '\\'; } // Initialize directories with the final directory var directories_backwards = [dirname]; var minimize_dir = dirname; while (minimize_dir = minimize_dir.substring(0, minimize_dir.lastIndexOf(slash))) { directories_backwards.push(minimize_dir); } var directories_needed = []; // Stop on the first directory found for(const d in directories_backwards) { if(!(fs.existsSync(directories_backwards[d]))) { directories_needed.push(directories_backwards[d]); } else { break; } } // No directories missing if(!directories_needed.length) { return resolve(); } // Make all directories in ascending order var directories_forwards = directories_needed.reverse(); for(const d in directories_forwards) { fs.mkdirSync(directories_forwards[d]); } return resolve(); }); } 

Comments

0

I could not find an example to create directories with the required permissions.

Create directories async recursively with the permissions you want.

Here’s a plain Node.js solution:

Code

// ----------------------------- const fs = require('fs'); const fsPromises = fs.promises; const checkDirAccess = async (userDir) => { try { await fsPromises.access(userDir, fs.constants.R_OK | fs.constants.W_OK); console.log(` ${userDir} Dir existss`); return userDir; } catch (err) { if(err.errno = -2) return await crDir(userDir); else throw err; } } const crDir = async (userDir) => { try { let newDir = await fsPromises.mkdir(userDir, { recursive: true, mode: 0o700}); // When userDir is created; newDir = undefined; console.log(` Created new Dir ${newDir}`); return newDir; } catch (err) { throw err; } } const directoryPath = ['uploads/xvc/xvc/xvc/specs', 'uploads/testDir11', 'uploads/xsXa/', 'uploads//xsb//', 'uploads//xsV/']; const findDir = async() => { try { for (const iterator of directoryPath) { let dirOK = await checkDirAccess(iterator); if(dirOK) console.log(`found ${dirOK}`) } } catch (error) { console.error('Error: ', error); } } 

Comments

-1

Exec can be messy on Windows. There is a more "nodie" solution.

Fundamentally, you have a recursive call to see if a directory exists and dive into the child (if it does exist) or create it. Here is a function that will create the children and call a function when finished:

fs = require('fs'); makedirs = function(path, func) { var pth = path.replace(/['\\] + /g, '/'); var els = pth.split('/'); var all = ""; (function insertOne() { var el = els.splice(0, 1)[0]; if (!fs.existsSync(all + el)) { fs.mkdirSync(all + el); } all += el + "/"; if (els.length == 0) { func(); } else { insertOne(); } })(); } 

1 Comment

What is "Exec"? Literal? "Execution"?
-1

This version works better on Windows than the top answer, because it understands both / and path.sep, so that forward slashes work on Windows as they should. It supports absolute and relative paths (relative to the process.cwd).

/** * Creates a folder and if necessary, parent folders also. Returns true * if any folders were created. Understands both '/' and path.sep as * path separators. Doesn't try to create folders that already exist, * which could cause a permissions error. Gracefully handles the race * condition if two processes are creating a folder. Throws on error. * @param targetDir Name of folder to create */ export function mkdirSyncRecursive(targetDir) { if (!fs.existsSync(targetDir)) { for (var i = targetDir.length-2; i >= 0; i--) { if (targetDir.charAt(i) == '/' || targetDir.charAt(i) == path.sep) { mkdirSyncRecursive(targetDir.slice(0, i)); break; } } try { fs.mkdirSync(targetDir); return true; } catch (err) { if (err.code !== 'EEXIST') throw err; } } return false; } 

2 Comments

Was the downvote for supporting Windows correctly? Did I mention it works on other OSs too?
What is "the top answer"? Which one? There is an accepted answer, but another has more (net) votes.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.