Library / SDK
libfuse/libfuse avatar
libfuse/libfuse

libfuse: building a Linux filesystem in userspace with the reference FUSE library

The reference implementation of the Linux FUSE (Filesystem in Userspace) interface

6,145 stars1,287 forksCNOASSERTION

At a glance

What is it?
libfuse is the userspace half of FUSE, the interface that lets an ordinary program serve a filesystem to the Linux kernel. It ships with every major distribution, but the README is candid that no one is actively developing it.
Who is it for?
Adopt libfuse if you need a Linux filesystem that lives in a normal process, and pick the high-level API unless you have a reason to manage inodes and replies yourself. Do not adopt it expecting an actively developed dependency: the README states there are no active, regular contributors and that the maintainer applies pull requests and cuts releases but has no capacity for development beyond high-impact issues.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What libfuse actually is, and the problem it removes

FUSE stands for Filesystem in Userspace. The README describes it as an interface for userspace programs to export a filesystem to the Linux kernel, and it splits cleanly into two parts: the fuse kernel module, maintained in the regular kernel repositories, and libfuse, the userspace library maintained in this repository. libfuse is the reference implementation for talking to that kernel module.

The problem it solves is concrete. Without FUSE, a new filesystem means kernel code: a module that hooks into the VFS, handles page cache interaction, and can take the whole machine down when it misbehaves. With libfuse, a filesystem is a standalone application that links against the library. libfuse provides the functions to mount the filesystem, unmount it, read requests from the kernel, and send responses back. Your code is a set of callbacks, not a kernel module.

That trade is not free. Every operation crosses the kernel boundary and lands in a userspace process, which is slower than an in-kernel filesystem and adds a process to the picture. For the workloads FUSE is normally used for (network filesystems, archive and container overlays, virtual views of remote storage, development tools that want to look like files) that cost is the price of not writing and maintaining kernel code.

The audience is C programmers writing such a filesystem, and, indirectly, everyone else: the README states libfuse is shipped by all major Linux distributions and has been in production use across a wide range of systems for many years.

High-level and low-level APIs: the choice that shapes your code

libfuse offers two APIs, and the difference is not cosmetic.

The high-level, synchronous API passes incoming kernel requests to your program through callbacks that work with file names and paths rather than inodes. Processing finishes when your callback returns. You write functions that receive a path, do something, and return a status. This is the API most people want.

The low-level, asynchronous API is the other end. Callbacks work with inodes, and responses must be sent explicitly through a separate set of API functions. Nothing is finished until you say it is. That is more bookkeeping, but it is what you need when a single request cannot be answered immediately, when you want to control the order in which replies go back, or when path-based lookup is the wrong model for what you are exposing.

The documentation for both lives in the headers: include/fuse.h for the high-level API and include/fuse_lowlevel.h for the low-level API. An autogenerated HTML version is available in doc/html and at the project's Doxygen site. The repository also carries examples under example/, including hello.c and hello_ll.c, which are the natural first reads for the two APIs, plus passthrough.c and passthrough_fh.c, which the README calls out as mirroring the contents of the root directory under the mountpoint.

One detail worth noticing in the layout: the examples include cuse.c and ioctl.c alongside the filesystem ones. CUSE is the character device counterpart to FUSE, and libfuse covers it too, which is easy to miss if you only read the filesystem framing.

Installing libfuse from a release tarball and running the passthrough example

The README does not tell you to clone the repository for a normal install. It tells you to download libfuse from the GitHub releases page and build with Meson and Ninja. Releases are signed, and the verification step comes first. The fuse-X.Y.pub file contains the signing key and has to be obtained from a trustworthy source; each release contains the signing key for the release after it in the signify directory, so you only need to fetch that file manually the first time.

bash
signify -V -m fuse-X.Y.Z.tar.gz -p fuse-X.Y.pub

If that reports the signature is fine, extract the tarball, create a build directory, and run Meson:

bash
tar xzf fuse-X.Y.Z.tar.gz; cd fuse-X.Y.Z
mkdir build; cd build
meson setup ..

The README states the default build options normally work. If you want to see what can be changed, meson configure lists the options and sets them:

bash
meson configure
meson configure -D disable-mtab=true
meson setup --reconfigure ../

The reconfigure step is the one people skip. Without it, changed options are not applied to the final build system.

Build, test, and install with Ninja:

bash
ninja
sudo ../test/run-tests.py --build-dir .
sudo ninja install

Running the tests needs bash, Python 3, and gdb (the last to resolve core dumps). The README notes that most tests can run as a regular user if util/fusermount3 is made setuid root first, in which case the rest skip themselves:

bash
../test/run-tests.py --build-dir . --setuid-helpers

Each test gets its own working and log directory, and the runner prints what every one cost. For a first real use, the README points at the example filesystems: start from the passthrough examples, which mirror the contents of the root directory under the mountpoint, and adapt the code. Both the example README and the test case README explain where to look when something fails.

fusermount3 is setuid root, and what that buys and costs

The fusermount3 program is installed setuid root. That is deliberate: it is what lets an ordinary user mount their own filesystem without root. The README also notes that if built, fuservicemount3 is installed setuid root as well, so normal users can access containerized filesystem implementations.

Because a setuid binary is a privilege boundary, fusermount3 enforces limits. A user can only mount on a mountpoint for which they have write permission. The mountpoint must not be a sticky directory that the user does not own, which rules out the usual /tmp case. And by default no other user, root included, can access the contents of the mounted filesystem. That last restriction can be relaxed by allowing the allow_other and allow_root mount options in /etc/fuse.conf.

That relaxation is where the sharp edge is. The README documents an unresolved security bug, known since 2006 and still unfixed because it needs a change in the Linux kernel: if the default_permissions mount option is not used, the result of the first permission check the filesystem performs for a directory entry is reused for later accesses as long as that entry's inode stays in the kernel cache. Permissions can change, and a different user can be the one making the later access, and the cached result still applies.

For a filesystem only the mounting user can reach, this matters little: that user has full access anyway. It becomes a real problem as soon as allow_other lets other users in, because they can use the stale result to perform operations they do not have permission for. The README gives two workarounds: use default_permissions (which does not currently support ACLs), or disable caching of directory entry attributes entirely. Neither is free, and the choice between them depends on whether you can give up ACLs or caching.

Where libfuse is the wrong tool

The clearest boundary is the platform one. Linux is fully supported. BSD is described as mostly or best-effort. For macOS the README does not offer a build path at all; it points at macFUSE. If your filesystem has to run on a Mac, you are not building against this repository.

The second boundary is performance. The design puts a userspace process between the kernel and your storage. If you are writing something that should behave like a local disk under heavy load, an in-kernel filesystem is the right shape, and libfuse is not.

The third is the permission model. If your filesystem will be mounted with allow_other and multiple users with different rights will touch it, the unresolved caching bug means you are choosing between default_permissions without ACLs and disabling directory entry attribute caching. If your design depends on ACLs and correct per-user permission checks at the same time, libfuse as documented here cannot give you both.

The fourth is project health, and it is the one people underestimate. The README states plainly that libfuse does not have any active, regular contributors. The current maintainer applies pull requests and makes regular releases but has no capacity for development beyond addressing high-impact issues. The README also warns that unless you include a pull request or are reporting a critical issue, you will probably not get a response. That is an honest statement, not a hidden risk, but it changes what you are adopting: a stable, widely deployed library that is maintained rather than developed. If your plan requires a new feature in libfuse itself, the README is telling you where that work will have to come from.

Alternatives, and the difference that matters

The most common alternative is not another library but another version of this one. The related searches include libfuse 2, libfuse 2 vs 3, and libfuse so 2, which reflects a real split: FUSE 2 and FUSE 3 are different API generations, and code written against the older one does not simply build against the newer one. If you are starting fresh, this article describes the current release line, fuse-3.18.x. If you are maintaining something already written against the 2.x API, the difference in approach is not philosophical; it is which set of callbacks and structures your code is built on, and moving means rewriting against the newer headers.

On macOS, the named alternative is macFUSE, and the difference is fundamental rather than stylistic: macFUSE is a separate project that provides the FUSE mechanism on that platform. The libfuse README does not claim to cover it.

The other alternative is the one libfuse exists to avoid: writing a kernel filesystem. That gives you the performance and the native permission handling, at the cost of kernel code, kernel review, and a much higher blast radius when something goes wrong. The difference in approach is where the code runs. libfuse keeps it in a process you can debug, restart, and kill; a kernel filesystem does not offer that.

Both APIs in libfuse are C. The repository's example directory contains memfs_ll.cc and cxxopts.hpp, so C++ is clearly exercised in the examples, but the library's own documentation is the C headers.

Maintenance, releases, and what the licence files say

The last push to the repository was on 2026-09-20, and the most recent release in the repository is fuse-3.18.3 from 2026-09-08, preceded by fuse-3.18.2 in March 2026 and fuse-3.18.1 in December 2025. So releases are happening on a rough cadence of a few months, and the repository is not archived.

None of that contradicts the README's own statement that there are no active, regular contributors. Releases and maintenance are not the same thing as development, and the README distinguishes them explicitly: pull requests are applied, releases are made, and development beyond high-impact issues does not happen. When you plan an upgrade, plan it as consuming someone else's release, not as requesting a change and waiting for it.

The upgrade cost itself is low for a library: build with Meson and Ninja, run the test suite, install. The test runner is part of the source tree and requires bash, Python 3, and gdb, with the setuid-helper path available for non-root runs. The bigger cost is the FUSE 2 to FUSE 3 API move if you have old code.

On licensing, the top-level directory contains LICENSE, GPL2.txt, and LGPL2.txt. The repository metadata reports the licence as NOASSERTION, which means the machine-readable field does not resolve to a single SPDX identifier. The practical consequence is that you should read those files yourself and determine which one applies to the parts you link against. That is a question for your own legal review, not something the repository metadata answers for you. The requirements.txt file is worth noting separately: it lists meson, ninja, and codechecker, and its own comment states these are for building and testing libfuse only, with no Python code required when using libfuse.

Editorial conclusion

Adopt libfuse if you need a Linux filesystem that lives in a normal process, and pick the high-level API unless you have a reason to manage inodes and replies yourself. Do not adopt it expecting an actively developed dependency: the README states there are no active, regular contributors and that the maintainer applies pull requests and cuts releases but has no capacity for development beyond high-impact issues. Before you commit, check three things in your own tree: whether your build can use Meson and Ninja, whether your filesystem will be mounted with allow_other, and if so whether you can live with default_permissions as the workaround for the directory entry permission caching bug. If your target is macOS, the README points at macFUSE instead.

Frequently asked questions

How do I install libfuse?

Download the release tarball from the GitHub releases page, verify it with signify against the fuse-X.Y.pub signing key, then build with Meson and Ninja: meson setup .., ninja, and sudo ninja install. The README states the default build options normally work, and that you should run meson setup --reconfigure ../ if you change any option with meson configure.

Is FUSE a kernel module?

The README describes the FUSE project as two components: the fuse kernel module, maintained in the regular kernel repositories, and libfuse, the userspace library maintained in this repository. libfuse is the reference implementation for communicating with that kernel module.

What is a FUSE filesystem?

The README defines FUSE as an interface for userspace programs to export a filesystem to the Linux kernel. A FUSE filesystem is typically implemented as a standalone application that links with libfuse, which provides the functions to mount the filesystem, unmount it, read requests from the kernel, and send responses back.

What is libfuse compared with libfuse 2?

libfuse 2 and libfuse 3 are different API generations of the same library, and this article describes the current fuse-3.18.x release line. The README documents the two APIs available in the current line, a high-level synchronous API working with paths and a low-level asynchronous API working with inodes and explicit responses, and code written against the older generation does not simply build against the newer one.

How do I install libfuse on Arch?

The README gives one installation route for libfuse itself: download the signed release tarball from the GitHub releases page and build it with Meson and Ninja. It states that libfuse is shipped by all major Linux distributions, so distribution packaging is the other route, but the README does not document Arch-specific package names or commands.

What is libfuse so 2?

The repository does not document a file named libfuse.so.2. The README covers libfuse as the userspace library that provides the reference implementation for communicating with the FUSE kernel module, and it notes that each release contains the signing key for the release after it in the signify directory. Anything about a specific shared object file name is not addressed there.

Official sources

  1. Issues
  2. libfuse/libfuse on GitHub
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/libfuse-libfuse.svg)](https://hysenlabs.com/projects/libfuse-libfuse)