Quick Start

Install mountx, test a driver, and create a mount.

#Install

npm i mountx

Warning

Pre-1.0 API. Breaking changes can occur. After you mount a driver, every program on the host can reach it.

#Step 0 — see one without writing one

The package includes a command-line interface (CLI). It mounts a prepared in-memory filesystem and prints each kernel request. You do not need root on Linux or macOS.

npx mountx                       # mounts ~/mountx
npx mountx /tmp/scratch -t nfs   # somewhere else, over a named transport
npx mountx --help

Open another terminal. Run ls -l ~/mountx and cat ~/mountx/README.md. The first terminal shows the requests. See The mountx CLI for all flags.

#Step 1 — no mounting at all

Start with createLoopback(). It lets you use a driver like fs/promises in the current process.

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 performs the same preparation as a real mount. It normalizes paths, returns ENOSYS for missing driver methods, and resolves capabilities. It does not create a mount and needs no root. It works on every platform, including Windows. Use it to develop and test drivers.

#Step 2 — mount it for real

Use the same driver as a directory that other programs on the host can open:

serve.ts
import { mount } from "mountx/auto";
import { createMemoryDriver } from "mountx/drivers/memory";

await using mounted = await mount(createMemoryDriver(), "/mnt/point");

mounted.transport; // "fuse" | "9p" | "nfs" — which one this host got

// /mnt/point is a real folder now. Keep the process alive.
await new Promise(() => {});

Run the server:

node serve.ts

Use the mount from another terminal. This requirement is important. See Do not use it from the same process.

echo hi > /mnt/point/hello.txt
cat /mnt/point/hello.txt
ls -l /mnt/point

Press Ctrl-C in the server terminal to remove the mount. await using also unmounts when its block ends. You can call await mounted.unmount() directly.

mount() from mountx/auto selects a usable transport for the host. It prefers FUSE on Linux and selects NFSv3 on macOS. The same code works on both platforms.

#Step 3 — serve a real folder

The node-fs driver sends requests to a real directory. It resolves each path component itself, so a request cannot reach data outside the root.

import { mount } from "mountx/auto";
import { createNodeFsDriver } from "mountx/drivers/node-fs";

await using mounted = await mount(createNodeFsDriver("/home/me/data"), "/mnt/point");

You can use this driver directly. You can also wrap it to add caching, logging, filtering, or data transformation.

#Do I need root?

Serving does not need privileges. Attaching the mount to a directory can need privileges. The requirement depends on the host and transport.

hosttransportroot?
Linux with fusermount3FUSEno
Linux without itFUSEyes
Linux without FUSE, with 9P9Pyes, always — 9P has no rootless path
macOSNFSv3no, but you must own the mount point
Linux (NFS pinned explicitly)NFSv3yes

On Linux, Node cannot make the mount system call. mountx asks fusermount3 to create the mount and return the connection. fusermount3 is the set-user-ID helper included with FUSE.

Most desktop Linux systems already include it.

Otherwise, install it with apt install fuse3 or dnf install fuse3.

When the process runs as root, mountx opens /dev/fuse and uses mount(8) directly.

9P has no helper like fusermount3, so it always needs root. For this reason, mountx/auto checks 9P only after FUSE. 9P provides real open and release state, which NFS does not provide.

On macOS, mountx uses NFSv3. /sbin/mount_nfs is not set-user-ID.

BSD systems let a user mount on a directory that the user owns.

You do not need sudo when you own the mount point.

FUSE and 9P do not apply on macOS. macFUSE is a third-party kernel extension with a different protocol.

BSD kernels do not have a v9fs client.

An unprivileged FUSE mount has two additional limits. allowOther needs user_allow_other in /etc/fuse.conf. Also, an unprivileged process cannot use umount -f to force an unresponsive mount down.

#Don't use it from the same process

A synchronous fs call to a mount served by the same process causes a deadlock.

A large number of concurrent asynchronous calls can also stop progress.

Put the client in another process, such as a shell or test child process.

See Troubleshooting.

#Where to go next

  • Writing a driver provides a complete filesystem in about 60 lines.
  • Mounting explains the mount object, lifecycle, and safe unmount.
  • Tuning explains cache settings that can improve speed by 10–15 times.
  • Troubleshooting covers stale mounts and deadlocks.

mountx  Write a filesystem in JavaScript, mount it as a real folder.