Open-source project
yandex-cloud/geesefs avatar
yandex-cloud/geesefs

GeeseFS: a fast FUSE filesystem over S3

Finally, a good FUSE FS implementation over S3

1,120 stars91 forksGoNOASSERTION

At a glance

What is it?
GeeseFS mounts an S3 bucket as a filesystem, and it exists because the usual way of doing that performs badly, especially with small files and metadata operations. Its answer is aggressive parallelism and asynchrony, and its honest limitation is a long list of POSIX features that only work fully on Yandex S3, where the object metadata is returned in listings.
Who is it for?
Adopt GeeseFS if you want a POSIX-shaped view of an S3 bucket and you are willing to accept its documented limits, no hard links, no locking, and a file size ceiling of about 1.03 TB by default. Do not adopt it as a general-purpose shared filesystem for applications that need hard links or locking, and do not expect the full POSIX feature set on Amazon S3, where the metadata-rich features are disabled by default.
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 24 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

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

Editorial analysis

The problem with putting S3 behind a filesystem

GeeseFS is a high-performance, POSIX-ish S3 file system written in Go, supporting Yandex S3 and Amazon S3, and it allows you to mount an S3 bucket as a file system.

The problem it names is the one everybody hits. FUSE file systems based on S3 typically have performance problems, especially with small files and metadata operations. A bucket is a key-value store reached over HTTP, and a filesystem is a tree of inodes that expects a stat call to be cheap. Every mismatch between the two costs a round trip, and the classic result is a directory listing that takes minutes.

GeeseFS's answer, stated in one line, is aggressive parallelism and asynchrony. Look at the performance table in the README and you can see what that means in practice. Parallel readahead, parallel multipart uploads, no readahead on random reads, server-side copy on append and on update, directory preload on file lookup, fast recursive listings, and asynchronous write, delete and rename. It has a disk cache for reads and for writes, where a cache that holds whole files is much less useful than a cache that holds blocks.

The comparison columns make the argument as well, against rclone, Goofys, S3FS and gcsfuse, with footnotes that are refreshingly blunt about where the alternatives fall down. The rclone mount VFS cache can only cache whole files, and it often hangs on write. S3FS uses a server-side copy but still downloads the whole file to update it, and is buggy. The recursive listing optimisation in Goofys is buggy and may skip files.

The POSIX matrix, and the rows that differ

The README publishes a compatibility matrix against rclone, Goofys, S3FS and gcsfuse, and it is the most useful page in the document for an adopter.

On the operations that matter for ordinary use, GeeseFS is in the positive column for read after write, partial writes, truncate, fallocate, fsync, directory renames and readdir with change notification. Those are the operations a build system, a package manager or a compiler needs, and being in the positive column for all of them is what makes a filesystem usable rather than a curiosity.

The rows where it differs are the interesting ones. chmod and chown are marked Y, which the legend explains as only working correctly with Yandex S3, and the same Y appears for symlinks, socket files, device files and custom mtime. xattr is marked with a plus rather than a Y, meaning supported in some form.

The reason for the Y is stated plainly and it is a good one. Standard S3 does not return user metadata in listings, and reading all of this metadata in standard S3 would require an additional HEAD request for every file in the listing, which would make listings too slow. So the choice is between correct metadata and usable listings, and GeeseFS keeps the listings fast.

The Goofys entry has its own footnote. Directory renames are allowed in Goofys for directories with no more than 1000 entries, and the limit is hardcoded.

The features that switch themselves off outside Yandex S3

The list of non-POSIX behaviours and limitations is the part of the README that deserves a careful reading before a mount.

Special file support, meaning block and character devices, named pipes and UNIX sockets, is enabled by default for Yandex S3 and disabled for others, with --no-specials to turn it off. File mode, owner and group are disabled by default even for Yandex S3, enabled with --enable-perms, and when disabled the global permissions can be set with the --(dir|file)-mode and --(uid|gid) options. Custom modification times are also disabled by default even for Yandex S3, enabled with --enable-mtime, and when they are disabled the ctime, atime and mtime are always the same and the modification time cannot be set by the user, for example with cp --preserve, rsync -a or utimes(2).

Three outright absences follow. It does not support hard links, it does not support locking, and it does not support invisible deleted files, meaning that if an application keeps an opened file descriptor after deleting the file, it will get ENOENT errors from filesystem operations.

And then a limit that is easy to miss. The default file size limit is 1.03 TB, achieved by splitting the file into 1000 parts of 5 MB, 1000 parts of 25 MB and 8000 parts of 125 MB. The part sizes can be changed, and the README notes that AWS's own limit is 5 TB anyway.

Partial object updates, and a cheaper fsync

There is a feature in the README that deserves its own section, because it is the one place where the implementation is genuinely ahead of the object store underneath it.

With Yandex S3 it is possible to do partial object updates, data only, without a server-side copy or a reupload. The feature is enabled with --enable-patch, and the README says it will be enabled by default for YC S3 in the future.

The benefits are listed and they are worth reading in order, because they compound. Fast fsync, since nothing needs to be copied. Support for concurrent updates, so two processes writing different parts of a file no longer conflict through a whole-object rewrite. Better memory utilisation, because less intermediate state needs to be cached, so more memory is available for the metadata and data cache. And better performance for big files.

The caveat is stated too. New files, metadata changes and renames are still flushed to S3 as multipart uploads. So the optimisation applies to updates of existing data, not to the whole object lifecycle, and a workload that mostly writes new files will see less of the benefit than one that rewrites parts of large objects in place.

The related footnotes place the feature in the wider table. Partial object updates only work with Yandex S3, and xattrs without an extra round trip only work there too, with the list-type=ext-v1 option.

Installing it, and mounting a bucket

Pre-built binaries are published for the main platforms, and each one names the FUSE prerequisite you need. On Linux amd64 you may also need to install the FUSE utilities, fuse3 or the fuse RPM or Debian package. On Mac there are amd64 and arm64 builds and you need osxfuse or macfuse. On Windows x64 you need WinFSP installed first.

Building from source is three commands, with the README saying Go 1.13 or later:

shell
git clone https://github.com/yandex-cloud/geesefs
cd geesefs
go build

The go.mod in the repository asks for a much newer toolchain than that, 1.25.9, so the README's stated minimum is out of date and the manifest is the authority.

Mounting uses the usual credentials file, which is the standard AWS shape:

shell
$ cat ~/.aws/credentials
[default]
aws_access_key_id = AKID1234567890
aws_secret_access_key = MY-SECRET-KEY
$ $GOPATH/bin/geesefs <bucket> <mountpoint>

The Go daemon library is in the dependency list alongside the FUSE bindings, and the go.mod pins cgofuse for Windows, which is how the WinFSP path is implemented.

Where GeeseFS is the wrong choice

The first wrong-tool case is a workload that needs hard links or file locking. Both are listed as unsupported, and neither is exotic. A build system that hard-links object files, an editor that locks a file to prevent concurrent edits, or a package manager that relies on rename-over semantics are all things a plain filesystem does and this one does not.

The second is a team that wants a shared filesystem rather than an object store view. A bucket mounted over FUSE is not NFS, it has no central locking, and the visibility of a write depends on the cache and the eventual consistency of the underlying store. A file that another host wrote may not appear immediately, and the same path on two hosts is not guaranteed to be coherent. For a shared workspace, a real filesystem is the right tool.

The third is an application that deletes a file while another process holds it open. The README is explicit that this results in ENOENT errors, and for a build system or an editor that keeps descriptors open, that is a class of failure that is tedious to debug.

There is also the metadata question to weigh for a non-Yandex user. Permissions, symlinks, special files and custom timestamps are all off by default on Amazon S3, so a POSIX-shaped workflow that depends on them will not behave as expected until you have accepted the listing slowdown, if you can.

The licence, the version line and the test rig

The licence is a custom one that GitHub files under Other, with the terms in the LICENSE file, and the root also carries an Apache-2.0.txt file, an AUTHORS file and a README-azure.md.

The release line is regular patch releases, v0.43.9 from 2026-09-03, v0.43.8 from 2026-06-22 and v0.43.7 from 2026-05-05, and the repository is not archived with the last push on 2026-09-29. The project sits in the 0.4x line, which fits a filesystem that is stable in behaviour but still being tuned.

The test infrastructure is the most reassuring part of the repository. The Makefile exports CGO_ENABLED=0, and the run-test target depends on s3proxy.jar, which is downloaded from the s3proxy project, so the test suite runs against a local S3 emulator rather than a real cloud. The run-xfstests target clones the xfstests suite from kdave and applies a patch from the test directory, which is the standard way to run the Linux filesystem conformance tests.

And the stability claim in the README is specific rather than vague. GeeseFS is stable enough to pass most of the applicable xfstests, including the dirstress and fsstress stress tests, with the generic cases 007, 011 and 013 named. For a filesystem, that is the evidence that matters, and the fact that the test rig is in the repository rather than described in a wiki is what makes it checkable.

Editorial conclusion

Adopt GeeseFS if you want a POSIX-shaped view of an S3 bucket and you are willing to accept its documented limits, no hard links, no locking, and a file size ceiling of about 1.03 TB by default. Do not adopt it as a general-purpose shared filesystem for applications that need hard links or locking, and do not expect the full POSIX feature set on Amazon S3, where the metadata-rich features are disabled by default. Before you mount it, read the non-POSIX behaviour list in the README, decide whether you need permissions, symlinks, custom timestamps or partial updates, and check whether the default multipart part sizes fit your largest objects.

Frequently asked questions

What is GeeseFS and what problem does it solve?

It is a high-performance, POSIX-ish S3 file system written in Go that mounts an S3 bucket as a filesystem. It targets the performance problems of FUSE over S3, especially with small files and metadata operations, using aggressive parallelism and asynchrony.

Which POSIX features work correctly only on Yandex S3?

File mode, owner and group, symbolic links, custom modification times and special files are restored correctly only with Yandex S3, because standard S3 does not return user metadata in listings and reading it would need a HEAD request per file. On other clouds these features are disabled by default and can be turned on with --enable-perms and --enable-mtime.

How do I install and mount GeeseFS?

Pre-built binaries exist for Linux amd64, Mac amd64 and arm64 and Windows x64, each needing its FUSE prerequisite such as fuse3, osxfuse or WinFSP. Or build with go build after cloning, then run the binary with a bucket and a mountpoint, using credentials in ~/.aws/credentials.

What are the limits of GeeseFS?

It does not support hard links, does not support locking, and does not support invisible deleted files, so an open descriptor after a delete gives ENOENT. The default file size limit is 1.03 TB, achieved by splitting files into parts of 5 MB, 25 MB and 125 MB.

What licence is GeeseFS released under?

A custom licence that GitHub files under Other, with the terms in the LICENSE file at the repository root alongside an AUTHORS file. The most recent release is v0.43.9 from 2026-09-03, and the last push was on 2026-09-29.

Official sources

  1. Issues
  2. README
  3. Releases
  4. yandex-cloud/geesefs on GitHub
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/yandex-cloud-geesefs.svg)](https://hysenlabs.com/projects/yandex-cloud-geesefs)

Was this useful?