Quick Start
From install to a real folder in about a minute.
#Install
npm i mountxWarning
Pre-1.0 API. Expect breaking changes, and note that a mounted driver is reachable by every program on the machine.
#Step 0 — see one without writing one
The package ships a CLI: a seeded in-memory filesystem, mounted for real, with every request the kernel makes printed as it happens. No root on either platform.
npx mountx # mounts ~/mountx
npx mountx /tmp/scratch -t nfs # somewhere else, over a named transport
npx mountx --helpThen poke at it from another terminal — ls -l ~/mountx, cat ~/mountx/README.md — and watch the requests scroll past. Full flags in The mountx CLI.
#Step 1 — no mounting at all
The fastest way to see mountx work is without touching the operating system. Wrap a driver in createLoopback() and use it like fs/promises, right inside your program:
import { createLoopback } from "mountx";
import { createMemoryDriver } from "mountx/drivers/memory";
const fs = createLoopback(createMemoryDriver());
await fs.mkdir("/notes");
await fs.writeFile("/notes/hello.txt", "hi");
const entries = await fs.readdir("/notes", { withFileTypes: true });
console.log(entries.map((entry) => entry.name)); // [ "hello.txt" ]
const bytes = await fs.readFile("/notes/hello.txt"); // Uint8Array
console.log(new TextDecoder().decode(bytes)); // "hi"createLoopback does the same tidying-up a real mount does: it normalizes paths, answers ENOSYS for methods your driver does not have, and resolves what your driver supports. Nothing is mounted, no root is needed, and it works on every platform — including Windows. This is where drivers get developed and tested.
#Step 2 — mount it for real
Same driver, now as a folder anyone on the machine can open:
import { mount } from "mountx/auto";
import { createMemoryDriver } from "mountx/drivers/memory";
await using mounted = await mount(createMemoryDriver(), "/mnt/point");
mounted.transport; // "fuse" | "nfs" — which one this host got
// /mnt/point is a real folder now. Keep the process alive.
await new Promise(() => {});Run it:
node serve.tsThen, from another terminal (this matters — see below):
echo hi > /mnt/point/hello.txt
cat /mnt/point/hello.txt
ls -l /mnt/pointPress Ctrl-C in the first terminal and the folder disappears. await using unmounts when the block ends; you can also call await mounted.unmount() yourself.
mount() from mountx/auto picks the transport this host can use — FUSE on Linux, NFSv3 on macOS — so that is the same code everywhere.
#Step 3 — serve a real folder
The second bundled driver hands requests to a real directory, resolving every path component itself so nothing outside the root can be reached:
import { mount } from "mountx/auto";
import { createNodeFsDriver } from "mountx/drivers/node-fs";
await using mounted = await mount(createNodeFsDriver("/home/me/data"), "/mnt/point");Useful on its own, and the easiest thing to build on: wrap it and you can add caching, logging, filtering or transformation to an ordinary directory.
#Do I need root?
Serving never needs privileges, on either transport. Only attaching the mount to a directory does, and how much depends on the host:
| host | transport | root? |
|---|---|---|
Linux with fusermount3 | FUSE | no |
| Linux without it | FUSE | yes |
| macOS | NFSv3 | no, but you must own the mountpoint |
| Linux (NFS pinned explicitly) | NFSv3 | yes |
On Linux, mounting is a syscall Node cannot make, so mountx asks fusermount3 — the setuid helper that ships with FUSE — to make it and hand the connection back. It is already installed on most desktop Linux; otherwise apt install fuse3 / dnf install fuse3. As root, mountx skips the helper and uses mount(8) directly.
On macOS you get NFSv3, and /sbin/mount_nfs is not setuid — macOS is a BSD, and a BSD lets an ordinary user mount onto a directory that user owns. So no sudo, as long as the mountpoint is yours.
Two things an unprivileged FUSE mount cannot do: allowOther additionally needs user_allow_other in /etc/fuse.conf, and forcing down a mount whose driver has stopped answering is weaker, because there is no umount -f without root.
#Don't use it from the same process
A synchronous fs call against your own mountpoint, from the process serving it, deadlocks. Enough concurrent async ones wedge it too. Put the client in another process — a shell, a test child process, anything. Full explanation in Troubleshooting.
#Where to go next
- Writing a driver — a complete filesystem in about 60 lines.
- Mounting — the mount object, lifecycle, and unmounting properly.
- Tuning — the cache settings that are worth 8–15×.
- Troubleshooting — stale mounts, wedges, and how to recover.