How to create a directory if it doesn’t exist using Node.js
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);
}
The code you provided is a reasonable approach but has some potential issues that should be addressed for more robust directory creation in Node.js. While it will work in many cases, there are better practices to follow, especially regarding permissions and error handling.
Contents
- Basic Directory Creation Methods
- Understanding Permission Modes
- Error Handling and Race Conditions
- Recursive Directory Creation
- Recommended Approaches
- Permission Best Practices
- Modern Node.js Solutions
Basic Directory Creation Methods
In Node.js, you have several options for creating directories:
Synchronous Approach (Your Current Method)
const fs = require('fs');
const path = require('path');
var dir = path.join(__dirname, 'upload');
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, 0744);
}
Asynchronous Approach (Recommended)
const fs = require('fs');
const path = require('path');
const dir = path.join(__dirname, 'upload');
fs.mkdir(dir, { recursive: true }, (err) => {
if (err) {
console.error('Error creating directory:', err);
} else {
console.log('Directory created successfully');
}
});
Understanding Permission Modes
Your code uses 0744 as the permission mode, but there are important caveats:
- Octal notation: Node.js expects permission modes in octal format (prefix with
0), so0744is correct - Actual permissions: The
0744mode gives:- Owner: read, write, execute (7)
- Group: read only (4)
- Others: read only (4)
However, research shows that the mode parameter in fs.mkdir() has inconsistent behavior across Node.js versions. According to Node.js GitHub issues, the actual permissions created may not match what you specify in the mode parameter.
Error Handling and Race Conditions
Your current approach has a potential race condition:
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, 0744);
}
Between the existsSync check and the mkdirSync call, another process could create the directory, causing an error. More robust solutions handle this error:
try {
fs.mkdirSync(dir, 0744);
} catch (err) {
if (err.code !== 'EEXIST') {
throw err; // Re-throw if it's not "directory already exists" error
}
}
Recursive Directory Creation
For creating nested directories (like path/to/nested/folder), you need the recursive: true option:
// Create nested directories
const nestedDir = path.join(__dirname, 'data', 'files', 'uploads');
fs.mkdirSync(nestedDir, { recursive: true, mode: 0o755 });
Without recursive: true, only the last directory in the path would be created, and it would fail if parent directories don’t exist.
Recommended Approaches
1. Simple Synchronous Method (with error handling)
const fs = require('fs');
const path = require('path');
function ensureDirectoryExists(dirPath, mode = 0o755) {
try {
fs.mkdirSync(dirPath, { recursive: true, mode });
return true;
} catch (err) {
if (err.code === 'EEXIST') {
return false; // Directory already exists
}
throw err; // Re-throw other errors
}
}
const dir = path.join(__dirname, 'upload');
ensureDirectoryExists(dir, 0o744);
2. Modern Async/Await Approach
const fs = require('fs').promises;
const path = require('path');
async function ensureDirectoryExists(dirPath, mode = 0o755) {
try {
await fs.mkdir(dirPath, { recursive: true, mode });
return true;
} catch (err) {
if (err.code === 'EEXIST') {
return false; // Directory already exists
}
throw err; // Re-throw other errors
}
}
// Usage
(async () => {
const dir = path.join(__dirname, 'upload');
await ensureDirectoryExists(dir, 0o744);
})();
Permission Best Practices
For full permission for the script and readable by others:
- Use
0o775for group collaboration scenarios - Use
0o755for standard web server directories - Use
0o777cautiously (full access to everyone)
Note that the actual permissions may also be affected by:
- The system’s umask setting
- File system restrictions
- Parent directory permissions
Modern Node.js Solutions
For Node.js v10.12.0 and above, the native fs.mkdir() with { recursive: true } is recommended over external libraries like mkdirp, unless you need to support older Node.js versions.
Your code evaluation:
var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
fs.mkdirSync(dir, 0744);
}
Pros:
- Simple and readable
- Uses existence check to avoid error
- Uses proper octal notation for permissions
Cons:
- Race condition between check and create
- No error handling for other potential errors
- Uses deprecated
path.existsSync()(consider usingfs.existsSync()) - Doesn’t handle recursive directory creation
- Permission mode behavior may be inconsistent
Improved version:
const fs = require('fs');
const path = require('path');
function safeCreateDirectory(dir, mode = 0o744) {
try {
fs.mkdirSync(dir, { recursive: true, mode });
} catch (err) {
if (err.code !== 'EEXIST') {
throw err;
}
}
}
const dir = path.join(__dirname, 'upload');
safeCreateDirectory(dir, 0o744);
This approach provides better reliability and follows Node.js best practices.
Sources
- How to create a directory if it doesn’t exist using Node.js - Stack Overflow
- Creating Directories in Node.js: A Guide to fs.mkdir() - Medium
- Node.js fs.mkdirSync() Method - GeeksforGeeks
- Using fs.mkdir() make a directory according the Docs the argument ‘mode’ defaults to 0o777, but actually it’s not - GitHub Issue
- mkdirp - npm
- Node.js — Working with folders in Node.js - Official Documentation
Conclusion
- Your current approach will work but has reliability issues
- Always handle errors when creating directories
- Use
{ recursive: true }for nested directory creation - Consider using async/await patterns for better performance
- Be aware that permission mode behavior can vary across Node.js versions
- For full script permissions and read access by others,
0o755or0o775are typically more appropriate than0o744
The improved solutions provided above offer better error handling, support for recursive directory creation, and follow modern Node.js best practices.