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

Features

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.

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