ZenFS Core
A cross-platform, in-process filesystem that mirrors Node's fs API in the browser, in Node, and anywhere JavaScript runs.
Repository Health
Technical Analysis
@zenfs/core is a TypeScript library that emulates the Node.js fs module so file-system code can run unmodified in the browser, in web workers, or in Node itself. It ships a single in-memory backend by default and lets you mount additional backends — IndexedDB, zip archives, a remote worker over MessagePort, copy-on-write layers, or a passthrough over an existing node:fs — at arbitrary paths, all through one declarative configure() call.
Every backend implements a small FileSystem/Backend contract, so the ecosystem extends through separate packages (@zenfs/dom, @zenfs/cloud, @zenfs/archives, @zenfs/emscripten) rather than growing the core. Sync and async operations are both supported on every backend via a shared mixin layer, error handling goes through a dedicated errno-style exception library, and the whole surface is covered by an extensive multi-threaded test suite.
What You Get
- A Node.js
fs-compatible API (sync, async, andfs/promises) usable as a default import. - Built-in backends:
InMemory,CopyOnWrite,Fetch(HTTP-backed),Port(cross-worker viaMessagePort),Passthrough(wraps an existingnode:fs), andSingleBuffer(SharedArrayBuffer-backed for multi-threaded sync access). - A declarative
configure({ mounts })API for mounting multiple backends at different paths in one call. - A typed
Backendcontract (create,options,isAvailable) for authoring custom backends that plug into the same VFS. - Structured, errno-coded exceptions (via the sibling
keriumpackage) instead of ad hoc thrown errors.
Common Use Cases
- Running file-dependent Node.js libraries or tests unmodified in a browser or web worker by swapping in ZenFS’s
fsshim. - Giving a web app a persistent, browser-native filesystem backed by IndexedDB or the File System Access API via the
@zenfs/dombackend. - Streaming remote archives (zip, ISO) or HTTP resources as a mounted, seekable filesystem via the
Fetchor@zenfs/archivesbackends. - Sharing a single filesystem across worker threads synchronously using the
SingleBufferbackend andSharedArrayBuffer.
Under The Hood
Architecture
ZenFS Core is organized into four layers: internal/ defines the core FileSystem interface, inode model, credentials/contexts, and errno-style exceptions that every backend must satisfy; backends/ holds the concrete implementations (memory, cow, fetch, passthrough, port, single_buffer, plus a store sub-layer); mixins/ composes cross-cutting capabilities (async, sync, mutexed, readonly) onto backend classes without duplicating logic per backend; and vfs/ implements the mount table, path resolution, permission/ACL checks, extended attributes, and file-watching that route calls to the right mounted backend. The public entry point re-exports all of these and layers a node/compat.js module on top that reproduces Node’s fs surface (sync, async, promises, streams, Dir), exposed as both a named fs export and the package default export, with a mutable globalThis.__zenfs__ escape hatch for cross-module state. Because every backend and every downstream package (@zenfs/dom, @zenfs/cloud, @zenfs/archives) depends on the shared FileSystem/Backend contract, changes to that core interface carry a wide blast radius across the whole ecosystem — mitigated by a small, explicit, self-describing contract (create, options, isAvailable).
Tech Stack
The library is written in strict-mode TypeScript targeting ES2022 with NodeNext module resolution, and keeps runtime dependencies minimal: eventemitter3 for events, readable-stream and a buffer polyfill for cross-platform stream/Buffer support, and two sibling packages by the same author — kerium for structured errno-style exceptions and memium/utilium for memory and type utilities. The build uses plain tsc, docs are generated with TypeDoc and deployed through a dedicated GitHub Actions workflow, linting runs through ESLint 10 with typescript-eslint, and formatting is enforced via Prettier. Testing runs on a custom zenfs-test CLI (in scripts/) layered on Node’s native test runner, with coverage collected via c8.
Code Quality
The repository ships roughly 40 test files spanning tests/common (path handling, case-folding, mutexes, config, contexts, inodes, globbing), tests/fs (the full Node fs API surface — append, concurrency, directories, errors, permissions, links, rename, and more), and tests/backend (backend-specific and worker-thread scenarios for cow, fetch, port, and single-buffer). Errors are raised as typed, errno-coded Exception objects carrying path and syscall context via wrap()/withExceptionContext() helpers, rather than bare thrown errors, and the source is densely annotated with TSDoc tags (@category, @internal, @deprecated) that feed the generated documentation site. strict: true plus typescript-eslint’s type-aware rules enforce type safety, and GitHub Actions workflows (ci.yaml, ci-pr.yaml) run lint and test on every pull request.
What Makes It Unique
The core ergonomic bet is a genuine drop-in replacement for node:fs — the same sync, async, and promise-based calls — so existing file-handling code can target ZenFS with a single import swap rather than a rewrite. On top of that compatibility layer, configure({ mounts }) gives a single declarative call to wire up multiple heterogeneous backends (in-memory, IndexedDB, a remote zip, a worker over MessagePort) at distinct mount points, and every included backend supports synchronous operations, including a SharedArrayBuffer-backed backend for synchronous cross-thread access — a capability that’s uncommon among browser-oriented filesystem shims. The tradeoff is that the mount/backend model is a step up in conceptual complexity over a single-backend library, and the fuller usage guide lives off-repo at zenfs.dev rather than as example files checked into the package.