unfs
A filesystem you can put in any key–value store.
import { createFs, initStore, memoryStore } from "unfs";
const fs = createFs(await initStore(memoryStore()));
await fs.mkdir("/docs");
await fs.writeFile("/docs/hello.txt", "hello unfs\n");
await fs.cp("/docs", "/backup", { recursive: true }); // O(1)
const pack = await fs.exportPackBytes("/"); // whole tree, one file
- A familiar API
A drop-in
node:fs/promises-style surface with node-shaped errors (ENOENT,EEXIST, …), plus a fully synchronous twin. - Bring your own store
Runs over any key–value backend — in-memory, on-disk, Redis, S3. If it can
getandputbytes, it can hold a filesystem. - Snapshots for free
Every write is a snapshot, identical content is stored once, and copying a directory is O(1).
- Deterministic
The same tree always comes out byte-identical — no timestamps sneak in unless you ask for them.
- Portable packs
Export any subtree to a single CARv1 file and import it into another store, hash-verified.
- Store-to-store sync
Mirror or pull refs over any byte stream — only the blocks the other side is missing move.
- Fast when you need it
Batch bulk writes into one snapshot (50×+ faster) and cache decoded nodes for 20–40× faster reads.
- Garbage collection
Mark & sweep with a write-free dry-run, to reclaim superseded snapshots.
- Zero dependencies
No runtime deps, no
node:imports in the core — strict ESM TypeScript, IPLD-compatible on the wire.