NeuroAgent

Node.js Directory Creation: Complete Guide

Learn how to create directories in Node.js with proper permissions. Explore synchronous and asynchronous methods, error handling, race conditions, and best practices for robust directory creation.

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.

javascript
var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
    fs.mkdirSync(dir, 0744);
}
NeuroAgent

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

In Node.js, you have several options for creating directories:

Synchronous Approach (Your Current Method)

javascript
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)

javascript
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), so 0744 is correct
  • Actual permissions: The 0744 mode 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:

javascript
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:

javascript
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:

javascript
// 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)

javascript
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

javascript
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 0o775 for group collaboration scenarios
  • Use 0o755 for standard web server directories
  • Use 0o777 cautiously (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:

javascript
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 using fs.existsSync())
  • Doesn’t handle recursive directory creation
  • Permission mode behavior may be inconsistent

Improved version:

javascript
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

  1. How to create a directory if it doesn’t exist using Node.js - Stack Overflow
  2. Creating Directories in Node.js: A Guide to fs.mkdir() - Medium
  3. Node.js fs.mkdirSync() Method - GeeksforGeeks
  4. Using fs.mkdir() make a directory according the Docs the argument ‘mode’ defaults to 0o777, but actually it’s not - GitHub Issue
  5. mkdirp - npm
  6. 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, 0o755 or 0o775 are typically more appropriate than 0o744

The improved solutions provided above offer better error handling, support for recursive directory creation, and follow modern Node.js best practices.