Skip to content

Repository files navigation

⛰️mountx

Warning

Alpha. Mountx is early development: the API can still change, and it has not been through a security or correctness audit. A driver is reachable by every program on the machine once it is mounted.

Write a filesystem in JavaScript, mount it as a real kernel filesystem.

You can write a driver with the same methods as node:fs/promises (stat, readdir, open, mkdir, rename). Mountx takes your driver and turns it into a real folder on the machine, so ls, cat, AI Agents, VSCode and any other program can use it.

There is no special API to learn: node:fs/promises already is the interface, and the errors it throws already are the error format.

So anything that behaves a bit like a filesystem can get a real path: an in-memory store, a zip file, an S3 bucket, a database, or a plain folder served back out with your own rules on top.

import { mount } from "mountx/auto";
import { createLoopback } from "mountx";
import { createMemoryDriver } from "mountx/drivers/memory";

// A driver is any object with stat(), readdir(), open(), [mkdir()] and [rename()] methods.
// Mountx has built-in memory, fs and unstorage drivers
const driver = createMemoryDriver();

// Work with FS in-process without mounting
const fs = createLoopback(driver);
await fs.mkdir("/notes");
await fs.writeFile("/notes/hello.txt", "hi!");
new TextDecoder().decode(await fs.readFile("/notes/hello.txt")); // "hi"

// Mount the driver to the kernel with whatever this host can use
// FUSE on Linux (no root needed), NFSv3 on macOS
await using mounted = await mount(driver, "/mnt/point", {
  fuse: { attrTimeout: 10 }, // seconds the kernel may cache attributes
});

/**
# /mnt/point is a real folder now, so every program on the machine can use it:
$ cat /mnt/point/notes/hello.txt   =>   hi!
$ echo hey > /mnt/point/notes/other.txt
**/

if (mounted.transport === "fuse") {
  mounted.notifyInvalInode(2n); // storage changed behind mountx's back? drop the cache
}

await mounted.unmount(); // or let `await using` do it at the end of the block

Install

npx nypm i mountx

Or mount a demo filesystem right now, and watch every request the kernel makes:

npx mountx

Documentation

mountx.vercel.app

  • Quick Start — install it and have a folder in about a minute.
  • Drivers — the three built-in ones, and the interface for writing your own.
  • Mountingmount(), the mount object, lifecycle and unmount.
  • Tuning — caching, concurrency, and the measured numbers.
  • Troubleshooting — the things that will bite you, and how to recover.
  • Transports — FUSE and NFSv3, what each costs, and how to pin one.
  • Reference — every entry point, option and type.

Development

local development
  • Clone this repository
  • Install the latest LTS version of Node.js
  • Enable Corepack with corepack enable
  • Install dependencies with pnpm install
  • Run tests in watch mode with pnpm dev
  • pnpm mountx runs the CLI (src/cli/index.ts) from source: it mounts an in-memory copy of this README at ~/mountx and logs every driver call it serves
  • pnpm test runs lint, typecheck and the suites that need no root; pnpm test:rootless adds the unprivileged real-mount suite (still no sudo); pnpm test:root adds the ones that do need it.
  • pnpm build:native rebuilds the FUSE mount helper with zig build and re-embeds it into native/prebuilt.mjs, which is the committed artifact — the .node files it is built from are gitignored. Only needed when native/src/ changes.
  • pnpm matrix and pnpm bench / pnpm bench:root regenerate the two committed reports the docs draw from (.agents/conformance-matrix.md, .agents/benchmarks.md).
  • The docs site is docs/, its own pnpm project: cd docs && pnpm install && pnpm dev.

License

Published under the MIT license 💛.

About

⛰️ Write a filesystem in JavaScript, mount it as a real kernel filesystem.

Resources

Stars

Watchers

Forks

Releases

Contributors

Languages