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.
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.
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 tomemfs.
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 Paritymemfs implements almost the entire fs API, including:
readFileSync, writeFileSync)readFile, writeFile)fs.promises.readFile)createReadStream, createWriteStream)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 Incompletememory-fs only implements a subset of basic synchronous methods. Missing features include:
fs.watchstat objects (e.g., missing mtime)// 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.
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.
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.
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.
If you’re stuck on memory-fs, migrating to memfs is usually straightforward:
new MemoryFileSystem() with vol from memfsvol.fromJSON() to seed initial statevol 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.
| Feature | memfs | memory-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) |
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.
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.
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.
In-memory file system with Node.js fs API and browser File System (Access) API.
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.
npm install memfs
fs APIimport { 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']
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!"
fs module API compatibilityfs and File System APIFor detailed documentation and more examples, visit the main project page.
Apache 2.0