Node.js needs a virtual file system

Node.js is introducing node:vfs, a core module that enables filesystem virtualization to solve long-standing issues with single executables, in-memory testing, and secure sandboxing.
Node.js has always been about I/O. Streams, buffers, sockets, files. The runtime was built from day one to move data between the network and the filesystem as fast as possible. But there’s a gap that has bugged me for years: you can’t virtualize the filesystem.
You can’t import or require() a module that only exists in memory. You can’t bundle assets into a single executable without patching half the standard library. You can’t sandbox file access for a tenant without reinventing fs from scratch.
That changes now. We’re announcing @platformatic/vfs, a userland Virtual File System for Node.js, and the upstream node:vfs module landing in Node.js core.
The problem
Here’s what it looks like in practice when Node.js doesn’t have a VFS:
- Bundle a full application into a Single Executable. You need to ship configuration files, templates, and static assets alongside your code. This often means bolting on 20 to 40 MB of extra boilerplate just to handle asset access at runtime. Node.js SEAs can embed a single blob, but your application code still calls
fs.readFileSync()expecting real paths, so you end up duplicating files or injecting glue code that bloats your binary. - Run tests without touching the disk. You want an isolated, in-memory filesystem so tests don’t leave artifacts and don’t collide in CI. Today, you mock fs with tools like
memfs, but those mocks don’t integrate withimportorrequire(). - Sandbox a tenant’s file access. In a multi-tenant platform, you need to confine each tenant to a directory without them escaping via
../. You end up writing path validation logic that’s fragile and easy to get wrong. - Load code generated at runtime. AI agents, plugin systems, and code generation pipelines produce JavaScript that needs to be imported. Today, that means writing to a temp file and hoping cleanup happens.
All four require the same primitive: a virtual filesystem that hooks into node:fs and Node.js module loading. The ecosystem has built approximations like memfs, unionfs, mock-fs, but they all share the same limitation: they patch fs but not the module resolver. Code that calls import('./config.json') bypasses them entirely.
node:vfs in Node.js core
I started working on a VFS implementation over Christmas 2025. What began as a holiday experiment became PR #61478: a node:vfs module for Node.js, with almost 14,000 lines of code across 66 files.
I built it with Claude Code. I pointed the AI at the tedious parts: implementing every fs method variant (sync, callback, promises), wiring up test coverage, and generating docs. I focused on the architecture, the API design, and reviewing every line.
Here’s what it looks like:
import vfs from 'node:vfs'
import fs from 'node:fs'
const myVfs = vfs.create()
myVfs.mkdirSync('/app')
myVfs.writeFileSync('/app/module.mjs', 'export default "hello from VFS"')
myVfs.mount('/virtual')
// Standard fs works
const data = fs.readFileSync('/virtual/app/module.mjs', 'utf8')
// import works, and so does require()
const mod = await import('/virtual/app/module.mjs')
console.log(mod.default) // "hello from VFS"
This is not a mock. When you call myVfs.mount('/virtual'), the VFS hooks into the actual fs module and the module resolver. Any code in the process that reads from paths under /virtual gets content from the VFS.
Why VFS needs to live in core Node.js
@platformatic/vfs proves why a userland implementation will always be a compromise:
- Module resolution is duplicated. Userland packages must re-implement complex logic for
node_modulesandpackage.jsonexports which already exists in core. - Private APIs. Before Node.js 23.5, there’s no public API to hook module resolution. Userland packages patch private internals that could break in any release.
- Global fs patching is fragile. If code captures a reference to
fs.readFileSyncbefore the VFS mounts, it bypasses the VFS. Core interception happens below the public API. - Native modules. A userland VFS can’t teach the native module loader to read
.nodefiles from memory. Core can. - Module cache cleanup. Core can track which modules came from which VFS and invalidate them on unmount, which is impossible for userland tools.
The PR is open and in active review. This feature will change how we build and deploy Node.js applications.
Source: Hacker News









