memfs vs memory-fs
In-Memory File System Implementations for Node.js
memfsmemory-fsSimilar Packages:
In-Memory File System Implementations for Node.js

memfs and memory-fs are both npm packages that provide in-memory implementations of Node.js's native fs module, enabling developers to simulate file system operations without touching the disk. These libraries are commonly used in testing, build tooling, and sandboxed environments where real I/O is either undesirable or impractical. While they serve similar purposes, they differ significantly in API fidelity, maintenance status, and compatibility with modern Node.js features.

Npm Package Weekly Downloads Trend
3 Years
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
memfs27,156,6192,02828.3 kB4811 days agoApache-2.0
memory-fs10,327,489879-306 years agoMIT

In-Memory File Systems in Node.js: memfs vs memory-fs

When you need to mock or simulate file system interactions in Node.js—whether for unit tests, build pipelines, or isolated development environments—an in-memory file system (IMFS) is often the right tool. Both memfs and memory-fs aim to replace Node’s built-in fs module with one that operates entirely in RAM. But their approaches, capabilities, and current viability differ dramatically. Let’s break down what each offers—and why one is clearly the better choice today.

🚫 Deprecation Status: One Is Officially Retired

memory-fs is deprecated.

As noted on its npm page and GitHub repository, memory-fs is no longer maintained. The author recommends using memfs instead. This isn’t just a minor detail—it means bugs won’t be fixed, security issues won’t be patched, and compatibility with newer Node.js versions isn’t guaranteed.

memfs is actively maintained, with regular updates, comprehensive test coverage, and explicit support for modern Node.js features.

Bottom line: Never start a new project with memory-fs. If you’re already using it, plan a migration to memfs.

🔧 API Completeness: How Closely Do They Mirror Node.js?

Node.js’s fs module has evolved significantly—adding promises (fs.promises), streams, and async iterators. A good IMFS should reflect this.

memfs: Near-Complete Parity

memfs implements almost the entire fs API, including:

  • Synchronous methods (readFileSync, writeFileSync)
  • Callback-based async methods (readFile, writeFile)
  • Promise-based methods (fs.promises.readFile)
  • Streams (createReadStream, createWriteStream)
  • Advanced features like fs.watch, fs.realpath, and symbolic links
// memfs example
import { fs } from 'memfs';

fs.writeFileSync('/test.txt', 'Hello world');
console.log(fs.readFileSync('/test.txt', 'utf8')); // 'Hello world'

// Works with promises too
await fs.promises.writeFile('/async.txt', 'Async content');
const data = await fs.promises.readFile('/async.txt', 'utf8');

It even supports volume mounting and custom roots, making it ideal for complex tooling like bundlers.

memory-fs: Limited and Incomplete

memory-fs only implements a subset of basic synchronous methods. Missing features include:

  • No promise support
  • No stream support
  • No fs.watch
  • Inconsistent behavior for stat objects (e.g., missing mtime)
  • Poor symlink handling
// memory-fs example (limited to sync ops)
const MemoryFileSystem = require('memory-fs');
const fs = new MemoryFileSystem();

fs.writeFileSync('/test.txt', 'Hello');
console.log(fs.readFileSync('/test.txt', 'utf8')); // works

// ❌ This will fail or behave unexpectedly:
// fs.createReadStream — not implemented
// fs.promises — doesn't exist
// fs.watch — not supported

Its stat objects often lack fields expected by real-world tools, causing subtle failures in integrations.

🧪 Real-World Integration: Testing and Tooling

With Jest or Mocha

memfs can cleanly replace fs in tests using vol (its volume system):

// Using memfs in a Jest test
import { vol } from 'memfs';
jest.mock('fs', () => require('memfs').fs);

beforeEach(() => {
  vol.fromJSON({ '/config.json': '{"debug":true}' });
});

afterEach(() => vol.reset());

test('reads config', () => {
  const config = require('fs').readFileSync('/config.json', 'utf8');
  expect(config).toContain('debug');
});

memory-fs requires manual instantiation and doesn’t integrate as smoothly. You can’t easily swap it for the real fs module because it doesn’t expose the same interface structure.

With Webpack or Rollup

Webpack’s in-memory output historically used memory-fs, but migrated to memfs in v5 due to reliability and feature gaps. If you’re building a custom plugin or loader, memfs is the only safe choice.

📁 File System Semantics: Does It Behave Like Real fs?

A good IMFS shouldn’t just look like fs—it should act like it.

  • memfs enforces real file system rules: you can’t read a file before it’s written, directories must exist before writing files into them (unless using recursive: true), and permissions are simulated.
// memfs throws correctly
fs.writeFileSync('/nonexistent/file.txt', 'data'); 
// → Error: ENOENT: no such file or directory

fs.mkdirSync('/dir', { recursive: true });
fs.writeFileSync('/dir/file.txt', 'ok'); // works
  • memory-fs is more permissive—it often lets you write to non-existent paths without error, which masks bugs during testing.
// memory-fs silently succeeds
fs.writeFileSync('/deep/nested/file.txt', 'data'); 
// No error, even though /deep/nested doesn’t exist

This leniency might seem convenient, but it leads to false confidence—code that passes tests with memory-fs may fail on real systems.

🔄 Migration Path: From memory-fs to memfs

If you’re stuck on memory-fs, migrating to memfs is usually straightforward:

  1. Replace new MemoryFileSystem() with vol from memfs
  2. Use vol.fromJSON() to seed initial state
  3. Access the file system via vol or fs = vol directly
// Before (memory-fs)
const fs = new MemoryFileSystem();
fs.writeFileSync('/a.txt', '1');

// After (memfs)
import { vol } from 'memfs';
vol.writeFileSync('/a.txt', '1');
// Or: const fs = vol;

Most basic read/write operations translate 1:1.

📊 Summary: Key Differences

Featurememfsmemory-fs
Maintenance Status✅ Actively maintained❌ Deprecated
Promise Support✅ Full (fs.promises)❌ None
Stream Support✅ Yes❌ No
fs.watch✅ Supported❌ Not implemented
Realistic Semantics✅ Enforces real fs rules⚠️ Overly permissive
Symbolic Links✅ Supported❌ Partial or broken
Webpack Compatibility✅ Used in Webpack 5+⚠️ Legacy (Webpack 4 and older)

💡 Final Recommendation

Use memfs—without hesitation—for any new work requiring an in-memory file system in Node.js. It’s the only option that’s both complete and actively supported.

Avoid memory-fs entirely unless you’re maintaining a legacy system that hasn’t yet been upgraded. Even then, prioritize migration.

In modern JavaScript development—where correctness, test fidelity, and integration with toolchains matter—there’s simply no reason to use a deprecated, incomplete alternative when a superior one exists.

How to Choose: memfs vs memory-fs
  • memfs:

    Choose memfs for new projects requiring a robust, actively maintained in-memory file system that closely mirrors Node.js's fs API—including support for promises, streams, and advanced features like fs.watch. It integrates seamlessly with tools like Webpack and Jest, and its design prioritizes correctness and completeness over minimalism.

  • memory-fs:

    Do not choose memory-fs for new projects—it is officially deprecated and no longer maintained. While it may suffice for legacy codebases that already depend on it and only require basic synchronous file operations, it lacks support for modern fs methods, promise-based APIs, and critical features like fs.stat consistency or symlink handling.

README for memfs

memfs

In-memory file system with Node.js fs API and browser File System (Access) API.

npm

Overview

memfs is a JavaScript library that implements an in-memory file system compatible with Node.js fs module and the browser File System (Access) API. Use it for testing, mocking file systems, or creating virtual file systems in both Node.js and browser environments.

Installation

npm install memfs

Quick Start

Node.js fs API

import { fs } from 'memfs';

// Write a file
fs.writeFileSync('/hello.txt', 'Hello, World!');

// Read a file
const content = fs.readFileSync('/hello.txt', 'utf-8');
console.log(content); // "Hello, World!"

// Create a directory
fs.mkdirSync('/mydir');

// List directory contents
console.log(fs.readdirSync('/')); // ['hello.txt', 'mydir']

Browser File System API

import { fsa } from 'memfs';

// Get root directory handle
const root = await fsa.getRoot();

// Create a file
const file = await root.getFileHandle('hello.txt', { create: true });
const writable = await file.createWritable();
await writable.write('Hello, World!');
await writable.close();

// Read the file
const readable = await file.getFile();
const text = await readable.text();
console.log(text); // "Hello, World!"

Features

  • Node.js fs module API compatibility
  • Browser File System (Access) API implementation
  • Adapters between fs and File System API
  • Directory snapshots and tree printing utilities
  • Works in Node.js and modern browsers
  • TypeScript support

Documentation

For detailed documentation and more examples, visit the main project page.

License

Apache 2.0