unfs
A filesystem you can put in any key–value store.

Files, directories, symlinks, permissions — and the node:fs API you already know — but no disk required. Every write is a snapshot, copies are O(1), and any tree packs into a single portable file.
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 get and put bytes, 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.