Node.js File System, Learn everything!

AsawerAsawer
4 min read

The fs module is a built-in Node.js module that allows interaction with the file system. It enables you to:

  • Create, read, write, and delete files and directories.

  • Manage file metadata.

  • Work with both synchronous and asynchronous operations.

1. Node.js fs Module Asynchronous/Synchronous Methods:

  • Asynchronous Methods:

    • Non-blocking (do not pause the execution of the program).

    • Use callbacks or promises to handle results.

    • Preferred for real-world applications to avoid blocking the event loop.

  • Synchronous Methods:

    • Blocking (execution halts until the operation completes).

    • Easier to understand but can degrade performance in large-scale applications.

    • Best for scripts or initialization tasks.


2. Difference Between Asynchronous and Synchronous Methods

Here’s an example that demonstrates the difference:

Asynchronous Example

const fs = require('fs');

console.log('Start');
fs.writeFile('example-async.txt', 'Hello, Async World!', (err) => {
  if (err) throw err;
  console.log('File created asynchronously');
});
console.log('End');

Output:

Start
End
File created asynchronously

Synchronous Example

const fs = require('fs');

console.log('Start');
fs.writeFileSync('example-sync.txt', 'Hello, Sync World!');
console.log('File created synchronously');
console.log('End');

Output:

Start
File created synchronously
End

Key Differences

FeatureAsynchronousSynchronous
ExecutionNon-blockingBlocking
PerformanceBetter for large-scale operationsSlows down the program
Error HandlingVia callback or promisesUses try-catch
Use CaseReal-time apps, serversInitialization scripts, small tasks

3. Core Operations: Create, Read, Append, Delete

We’ll go through each file system operation using both asynchronous and synchronous methods. Explanation accompanies every step.


3.1. Creating a Folder

Asynchronous

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

const folderPath = path.join(__dirname, 'myFolder');

// Create folder asynchronously
fs.mkdir(folderPath, { recursive: true }, (err) => {
  if (err) throw err;
  console.log('Folder created asynchronously!');
});

Synchronous

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

const folderPath = path.join(__dirname, 'myFolder');

// Create folder synchronously
fs.mkdirSync(folderPath, { recursive: true });
console.log('Folder created synchronously!');

3.2. Creating a File

Asynchronous

const filePath = path.join(folderPath, 'example.txt');
const content = 'Hello, this is a sample file content.';

// Create file asynchronously
fs.writeFile(filePath, content, (err) => {
  if (err) throw err;
  console.log('File created asynchronously!');
});

Synchronous

const filePath = path.join(folderPath, 'example.txt');
const content = 'Hello, this is a sample file content.';

// Create file synchronously
fs.writeFileSync(filePath, content);
console.log('File created synchronously!');

3.3. Reading a File

Asynchronous

fs.readFile(filePath, 'utf8', (err, data) => {
  if (err) throw err;
  console.log('File content (Async):', data);
});

Synchronous

const data = fs.readFileSync(filePath, 'utf8');
console.log('File content (Sync):', data);

3.4. Appending to a File

Asynchronous

const additionalContent = '\nThis is some appended content.';

// Append to file asynchronously
fs.appendFile(filePath, additionalContent, (err) => {
  if (err) throw err;
  console.log('Content appended asynchronously!');
});

Synchronous

const additionalContent = '\nThis is some appended content.';

// Append to file synchronously
fs.appendFileSync(filePath, additionalContent);
console.log('Content appended synchronously!');

3.5. Deleting a File

Asynchronous

fs.unlink(filePath, (err) => {
  if (err) throw err;
  console.log('File deleted asynchronously!');
});

Synchronous

fs.unlinkSync(filePath);
console.log('File deleted synchronously!');

3.6. Deleting a Folder

Asynchronous

fs.rmdir(folderPath, { recursive: true }, (err) => {
  if (err) throw err;
  console.log('Folder deleted asynchronously!');
});

Synchronous

fs.rmdirSync(folderPath, { recursive: true });
console.log('Folder deleted synchronously!');

4. Error Handling

Error handling ensures your app doesn’t crash unexpectedly. Always handle errors when performing file system operations.

Example with Asynchronous Operations

fs.readFile('nonexistent.txt', 'utf8', (err, data) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.error('File not found!');
    } else {
      throw err;
    }
    return;
  }
  console.log(data);
});

Example with Synchronous Operations

try {
  const data = fs.readFileSync('nonexistent.txt', 'utf8');
  console.log(data);
} catch (err) {
  if (err.code === 'ENOENT') {
    console.error('File not found!');
  } else {
    throw err;
  }
}

5. Practical Example: Complete Workflow

Let’s combine everything into a single workflow:

  1. Create a folder.

  2. Create a file inside it.

  3. Read the file content.

  4. Append more content.

  5. Delete the file.

  6. Delete the folder.

javascriptCopy codeconst folderPath = path.join(__dirname, 'myFolder');
const filePath = path.join(folderPath, 'example.txt');

// Create folder
fs.mkdir(folderPath, { recursive: true }, (err) => {
  if (err) throw err;
  console.log('Folder created.');

  // Create file
  fs.writeFile(filePath, 'Hello, World!', (err) => {
    if (err) throw err;
    console.log('File created.');

    // Read file
    fs.readFile(filePath, 'utf8', (err, data) => {
      if (err) throw err;
      console.log('File content:', data);

      // Append content
      fs.appendFile(filePath, '\nAppended Content!', (err) => {
        if (err) throw err;
        console.log('Content appended.');

        // Delete file
        fs.unlink(filePath, (err) => {
          if (err) throw err;
          console.log('File deleted.');

          // Delete folder
          fs.rmdir(folderPath, { recursive: true }, (err) => {
            if (err) throw err;
            console.log('Folder deleted.');
          });
        });
      });
    });
  });
});

6. Best Practices

  • Use asynchronous methods for non-blocking operations.

  • Prefer promises or async/await for cleaner asynchronous code.

  • Always handle errors gracefully.

  • Use path module for constructing cross-platform paths.

0
Subscribe to my newsletter

Read articles from Asawer directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Asawer
Asawer