fs vs fs-extra vs fs-extra-promise
File System Operations in Node.js
fsfs-extrafs-extra-promiseSimilar Packages:

File System Operations in Node.js

fs is Node.js's built-in module for file system operations, offering low-level access with callback, sync, and promise-based APIs. fs-extra extends fs with additional high-level utilities like recursive copy, directory creation, and JSON helpers, while providing native promise support. fs-extra-promise was a wrapper that added promise support to older versions of fs-extra, but it is now deprecated and should not be used in new projects.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
fs0164-410 years agoISC
fs-extra09,62356.8 kB122 months agoMIT
fs-extra-promise044-79 years agoMIT

File System Operations in Node.js: fs vs fs-extra vs fs-extra-promise

When building Node.js applications that interact with the file system β€” whether it’s reading configs, writing logs, or managing uploads β€” choosing the right tooling matters. The built-in fs module is always available, but many developers reach for higher-level packages like fs-extra or (historically) fs-extra-promise. Let’s compare them head-to-head from a practical engineering standpoint.

πŸ“¦ Core Capabilities and API Design

fs is Node.js’s native file system module. It provides low-level access to file operations with both callback-based and synchronous APIs. As of Node.js v10+, it also includes promise-based versions under fs.promises.

// fs: Callback style
const fs = require('fs');
fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

// fs: Promise style (Node.js >=10)
const { readFile } = require('fs').promises;
const data = await readFile('file.txt', 'utf8');

fs-extra extends fs with additional convenience methods (like copy, remove, ensureDir) and automatically promisifies all functions, so every method returns a promise without needing .promises.

// fs-extra: All methods are promise-friendly by default
const fse = require('fs-extra');
const data = await fse.readFile('file.txt', 'utf8');
await fse.ensureDir('./logs'); // creates dir if missing
await fse.copy('./src', './dest'); // recursive copy

fs-extra-promise was created as a wrapper around fs-extra to add explicit promise support before fs-extra did so natively. However, this package is now deprecated.

⚠️ Important: According to its npm page, fs-extra-promise is no longer maintained and explicitly states: "This package is deprecated. Use fs-extra directly instead."

// fs-extra-promise: Deprecated pattern (do not use in new code)
const fsep = require('fs-extra-promise');
// This just wraps fs-extra β€” redundant since fs-extra supports promises out of the box

πŸ”§ Key Feature Comparison

Recursive Directory Operations

Need to create nested directories or delete entire folders? fs requires manual recursion or external logic, while fs-extra handles it natively.

// fs: Manual effort for deep mkdir
const fs = require('fs');
fs.mkdirSync('./a/b/c', { recursive: true }); // supported since Node.js v10.12.0

// But for older versions or more complex cases, you’d need custom code

// fs-extra: Simple and consistent
const fse = require('fs-extra');
await fse.ensureDir('./deeply/nested/path'); // works everywhere
await fse.remove('./folder'); // deletes recursively, even if non-empty

Note: Modern fs does support { recursive: true } in mkdir and rm (since Node.js v14.14.0), but fs-extra’s ensureDir and remove remain more ergonomic and backward-compatible.

Copying Files and Directories

Copying a directory tree is non-trivial with raw fs. You’d need to walk the tree manually.

// fs: No built-in copy for directories β€” you must implement it
// (omitted for brevity β€” it’s dozens of lines)

// fs-extra: One-liner
await fse.copy('./source', './backup');

This alone makes fs-extra compelling for scripts, build tools, or CLI apps.

JSON Convenience Methods

Both fs and fs-extra let you read/write JSON, but fs-extra adds dedicated helpers:

// fs: Manual parse/stringify
const data = JSON.parse(await fs.promises.readFile('config.json', 'utf8'));
await fs.promises.writeFile('output.json', JSON.stringify(data, null, 2));

// fs-extra: Built-in
const data = await fse.readJson('config.json');
await fse.writeJson('output.json', data, { spaces: 2 });

Less boilerplate, fewer try/catch blocks for parse errors (it throws cleanly).

πŸ”„ Promise Support: Evolution Over Time

Early Node.js only offered callbacks. Developers used libraries like bluebird to promisify fs. Then fs-extra emerged, offering extra methods and promise support via optional wrappers.

Eventually, fs-extra baked in promise support by default (starting around v6+). This made fs-extra-promise obsolete β€” it was just an unnecessary layer.

Today:

  • fs.promises gives you native promises, but only for standard fs methods.
  • fs-extra gives you promises plus utility methods (copy, move, emptyDir, etc.).
  • fs-extra-promise adds nothing new and is deprecated.

πŸ›‘ Deprecation Status: What This Means for Your Codebase

The fs-extra-promise npm page clearly states:

"This package has been deprecated. fs-extra now includes promise support by default. Please use fs-extra directly."

Do not use fs-extra-promise in any new project. If you find it in legacy code, replace it with fs-extra and remove the extra dependency.

πŸ§ͺ Real-World Usage Scenarios

Scenario 1: Simple Config Reader in a Modern App

You’re on Node.js 18+ and just need to read a JSON config file.

  • βœ… Best choice: fs.promises
  • Why? Zero dependencies, native, sufficient for basic needs.
import { readFile } from 'fs/promises';
const config = JSON.parse(await readFile('app.json', 'utf8'));

Scenario 2: Build Script That Copies Assets and Cleans Output

You need to empty a dist/ folder, copy static files, and ensure log directories exist.

  • βœ… Best choice: fs-extra
  • Why? emptyDir, copy, and ensureDir save dozens of lines of error-prone code.
import fse from 'fs-extra';
await fse.emptyDir('dist');
await fse.copy('public', 'dist');
await fse.ensureDir('logs');

Scenario 3: Legacy Code Using fs-extra-promise

You inherit a codebase using require('fs-extra-promise').

  • βœ… Action: Replace with fs-extra and remove the deprecated package.
  • Why? Eliminates a dead dependency and aligns with current best practices.

πŸ“Š Summary Table

Featurefs (native)fs-extrafs-extra-promise
Promise supportβœ… via fs.promisesβœ… built-inβœ… (but redundant)
Recursive mkdir/rmβœ… (Node.js β‰₯10/14)βœ… (ensureDir, remove)βœ… (via fs-extra)
Directory copy/moveβŒβœ…βœ… (via fs-extra)
JSON helpersβŒβœ… (readJson, etc.)βœ… (via fs-extra)
Maintenance statusβœ… (core Node.js)βœ… actively maintained❌ deprecated
Extra dependenciesβŒβœ… (minimal)βœ… + deprecated wrapper

πŸ’‘ Final Recommendation

  • Use fs when you’re in a modern Node.js environment and only need basic file operations. It’s lightweight and dependency-free.
  • Use fs-extra when you want productivity boosts like recursive copy, safe directory creation, or JSON helpers β€” especially in scripts, CLIs, or tooling.
  • Never use fs-extra-promise β€” it’s deprecated and offers no advantage over plain fs-extra.

In most real-world Node.js projects beyond trivial examples, fs-extra pays for itself in reduced code complexity and improved reliability. Just remember: it’s a Node.js-only library, so don’t try to bundle it for the browser.

How to Choose: fs vs fs-extra vs fs-extra-promise

  • fs:

    Choose fs if you're working in a modern Node.js environment (v10+) and only need standard file operations like reading, writing, or deleting files. It requires no dependencies and integrates directly with Node.js core, making it ideal for minimal, performance-sensitive applications where you don't need convenience methods.

  • fs-extra:

    Choose fs-extra when you need robust, high-level file system utilities such as recursive directory copying, safe directory creation (ensureDir), or built-in JSON reading/writing. It’s particularly valuable in scripts, build tools, CLI apps, or any scenario where reducing boilerplate and handling edge cases (like missing parent directories) matters. All methods return promises by default, simplifying async code.

  • fs-extra-promise:

    Do not choose fs-extra-promise for any new project. It is officially deprecated, as fs-extra has included native promise support since version 6. Using it adds an unnecessary dependency and increases maintenance risk. If encountered in legacy code, migrate to fs-extra directly.

README for fs

Security holding package

This package name is not currently in use, but was formerly occupied by another package. To avoid malicious use, npm is hanging on to the package name, but loosely, and we'll probably give it to you if you want it.

You may adopt this package by contacting support@npmjs.com and requesting the name.