Node.js has a file system problem. Not a bug, exactly β more like an architectural blind spot that’s been quietly costing developers performance, security, and portability for years. Matteo Collina, CTO of Platformatic and one of the most influential voices in the Node.js community, laid out the argument in a recent Platformatic blog post that’s generating real conversation among backend engineers: Node.js needs a virtual file system.
The core idea isn’t exotic. A virtual file system (VFS) is an abstraction layer that sits between application code and the actual operating system’s file operations. Instead of reading and writing directly to disk, your code talks to an intermediary that can intercept, redirect, or transform those operations. Languages and runtimes like Go and Deno have already embraced variations of this concept. Node.js hasn’t. And that gap is starting to matter.
Collina’s argument centers on several pain points that any Node.js developer working at scale will recognize. First, there’s the bundling problem. Modern JavaScript tooling β think webpack, esbuild, Rollup β already performs a kind of virtual file system trick at build time, resolving modules from memory or transformed sources rather than raw disk reads. But Node.js itself has no native awareness of this. The runtime still assumes everything lives on a real filesystem, which creates friction when you’re trying to bundle a Node.js application into a single executable or deploy it in constrained environments like edge functions or containers.
Then there’s security. Direct filesystem access is a broad attack surface. A VFS could enforce fine-grained permissions β restricting which paths a module can read from, preventing writes to sensitive directories, sandboxing third-party dependencies. Deno took this approach from day one with its permissions model, and it’s one of the features that made Ryan Dahl’s newer runtime appealing to security-conscious teams. Node.js, by contrast, gives every require() and fs.readFile() call the same unrestricted access to the disk. That’s a liability.
Portability is the third leg of the argument. Serverless platforms, edge runtimes, and embedded environments don’t always have a traditional filesystem. Some have read-only filesystems. Some have no filesystem at all, just in-memory blobs. Without a VFS abstraction, Node.js applications targeting these environments need workarounds β polyfills, custom loaders, or platform-specific hacks that fragment the developer experience.
So why hasn’t this happened already?
Partly inertia. Node.js is over fifteen years old, and its filesystem APIs are among the most heavily used in the entire standard library. Introducing an abstraction layer underneath fs without breaking millions of existing applications is genuinely hard engineering. Partly politics β changes this fundamental require broad consensus across the Node.js Technical Steering Committee, and the community has historically been conservative about runtime-level abstractions that add indirection.
But the winds are shifting. Collina points to the Node.js Single Executable Application (SEA) initiative as evidence. SEA, which landed experimentally in Node.js 19 and has matured through subsequent releases, bundles a Node.js app and its assets into a single binary. The problem? It currently relies on injecting a virtual filesystem blob into the binary, but the runtime’s own module resolution doesn’t fully understand this. The result is a half-measure β functional, but brittle. A proper VFS would make single executables a first-class citizen rather than a clever workaround.
Platformatic has skin in this game. The company builds a platform for creating and deploying Node.js services, and Collina’s team has been working on solutions that compile applications with their dependencies into optimized bundles. Their experience trying to make this work cleanly within Node.js’s current architecture is what drove the blog post. It’s advocacy born from direct engineering pain, not theory.
The post also references prior art worth knowing about. Go’s embed package and io/fs interface let developers include static files directly in compiled binaries with full filesystem semantics. Deno’s snapshot mechanism and its built-in permissions model both rely on abstractions that a VFS would provide. Even within Node.js, the node:module customization hooks (formerly loaders API) represent a partial step β they let you intercept module resolution, but they don’t extend to general filesystem operations.
What would a Node.js VFS actually look like in practice? Collina suggests it should be transparent to existing code. Applications using fs.readFile or require shouldn’t need to change. The abstraction would live beneath those APIs, allowing the runtime β or an embedder β to swap in different backends. Real disk. In-memory. A compressed archive. A remote store. The application code stays the same.
Not everyone’s convinced. Some Node.js contributors have raised concerns about performance overhead β any abstraction layer adds indirection, and filesystem operations are already a common bottleneck. Others worry about complexity creep in a runtime that’s succeeded partly because of its relative simplicity compared to the JVM or .NET CLR.
Fair concerns. But the counterargument is straightforward: the abstraction is already happening, just badly. Every bundler, every single-executable tool, every edge runtime adapter is reinventing some version of a VFS in userland. Standardizing it at the runtime level would reduce duplication, improve interoperability, and open doors for optimizations that userland solutions can’t achieve β like kernel-level caching awareness or native integration with container overlay filesystems.
For engineering teams building on Node.js today, this is worth watching. The discussion is still in its early stages, and no formal TC39 or Node.js TSC proposal exists yet. But Collina’s track record β he’s a Node.js TSC member and the creator of Fastify and Pino β means this isn’t idle speculation. When he identifies a gap, things tend to move.
And honestly? As someone who’s been building with Node since the early days, I find the argument compelling. The runtime has always been pragmatic about adopting good ideas late β ES modules, worker threads, the test runner. A virtual file system feels like the next logical step. The question isn’t whether Node.js needs one. It’s whether the community can agree on the right design before the workarounds become too entrenched to replace.


WebProNews is an iEntry Publication